c++类开发的第三篇(讲明白友元函数和this指针)
friend_function
成员变量和函数的存储
c++实现了封装
,数据
和处理数据的操作(函数)
是分开存储的。
-
c++中的非静态数据成员直接内含在类对象中,就像c语言的struct一样。
-
成员函数并不会出现在对象中,而是作为类的一部分存储在代码段中,需要通过对象或对象指针进行调用。成员函数可以访问类的所有成员变量和成员函数,包括私有成员,但不能直接访问静态变量,需要使用类名或对象来访问。
-
每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.
class Regina02 {
public:
int a;
};
class Regina03 {
public:
int mA;
static int sB;
};
class Regina04 {
public:
void printMyClass() {
cout << "Regina04 void printMyClass()" << endl;
}
public:
int mA;
static int sB;
};
class Regina05 {
public:
void printMyClass() {
cout << "Regina05 void printMyClass()" << endl;
}
static void ShowMyClass() {
cout << "Regina05 static void ShowMyClass()" << endl;
}
在这四个类里面,后面一个类分别比前面一个类多一个成分,为了证实C++类对象中的变量和函数是分开存储,我们分别实例化四个对象打印大小
int main() {
Regina02 regina02;
Regina03 regina03;
Regina04 regina04;
Regina05 regina05;
cout << "Regina02:" << sizeof(regina02) << endl; //4
//静态数据成员并不保存在类对象中
cout << "Regina03:" << sizeof(regina03) << endl; //4
//非静态成员函数不保存在类对象中
cout << "Regina04:" << sizeof(regina04) << endl; //4
//静态成员函数也不保存在类对象中
cout << "Regina05:" << sizeof(regina05) << endl; //4
return 0;
发现所有的类对象大小都一样,对于静态成员变量和静态成员函数,它们并不属于类的对象,而是属于整个类本身。它们存储在静态数据区,而不是存储在类的对象中。静态成员变量在程序运行期间只有一份实体,不随类的对象的创建而分配内存,而静态成员函数也不依赖于特定的类对象。
this指针
通过上例我们知道,c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象。
c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。
this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认设置。
this指针使用
-
当形参和成员变量同名时,可用this指针来区分
-
在类的非静态成员函数中返回对象本身,可使用return *this.
class Use_this {
private:
string name;
int age;
public:
/*当形参名字和成员变量名字一样时,this指针可以区分*/
Use_this(string name, int age) {
// name = name; false
this->name = name;
this-> age = age;
}
//返回对象本身的引用
//重载赋值操作符
//其实也是两个参数,其中隐藏了一个this指针
Use_this personAdd(Use_this& person) {
string newname = this->name + person.name;
int newage = person.age + this->age;
Use_this newperson(newname, newage);
return Use_this(newname, newage);
}
void showPerson() {
cout << "name: " << name << "\n" << "age: " << age << endl;
}
};
int main(){
Use_this person1 = Use_this("regina ", 13);
Use_this person2 = Use_this("love Ivanlee", 14);
person1.showPerson();
Use_this person3 = person1.personAdd(person2);
person3.showPerson();
return 0;
}
const
当 const
关键字用于修饰成员函数时,它表示该成员函数是一个常量成员函数,也称为常成员函数。常成员函数有以下特点:
- 常成员函数不会修改对象的状态:常成员函数承诺不会修改类的任何非静态成员变量。这意味着在常成员函数内部,不能修改成员变量的值,除非该成员变量被声明为
mutable
。 - 常成员函数可以读取对象的状态:常成员函数可以访问和读取类的所有成员变量,包括非
const
成员变量。 - 常成员函数可以调用其他常成员函数:常成员函数可以调用其他常成员函数,因为它们都遵守不修改对象状态的承诺。
在 C++ 中,
mutable
是一个关键字,用于声明类的成员变量可以在常成员函数中被修改。通常情况下,常成员函数(被const
修饰的成员函数)不能修改类的成员变量,因为它们承诺不会改变对象的状态。然而,有时候我们可能需要在常成员函数中修改某些变量,这时就可以使用mutable
关键字。当一个成员变量被声明为
mutable
时,即使在常成员函数中,该成员变量仍然可以被修改。这样做的目的是为了允许在逻辑上不改变对象状态的情况下,修改一些与对象状态无关的数据。
在ida里面写代码的时候就能看到,当我们定义好了const成员函数时,没有定义过的mutable的变量是不可以修改的。
友元函数
友元函数存在的主要原因是为了提供更灵活的设计和实现方式,同时在某些特定情况下确实需要直接访问类的私有成员或保护成员。以下是一些使用友元函数的情况和原因:
- 访问私有成员:有时候在类的外部需要访问类的私有成员数据,但又不希望通过公有成员函数来实现。这种情况下,可以使用友元函数来实现对私有成员的直接访问,提高代码的封装性和安全性。
- 提高效率:有些操作可能需要直接访问类的私有数据,如果通过公有接口来访问可能会降低效率。通过友元函数可以避免频繁调用公有接口,提高程序执行效率。
- 实现非成员函数:某些操作与类密切相关,但又不属于类的成员函数的范畴,这时候可以使用友元函数来实现这样的操作。
- 重载运算符:在C++中,一些运算符如
<<
、>>
、+
等是可以重载的,如果想要对类进行运算符重载,并且需要直接访问类的私有数据,可以使用友元函数来实现。(后续会解释) - 类之间的协作:有时候多个类之间需要相互访问对方的私有成员,可以使用友元函数来实现类之间的协作。
友元语法
friend关键字只出现在声明处
其他类、类成员函数、全局函数都可声明为友元
友元函数不是类的成员,不带this指针
友元函数可访问对象任意成员属性,包括私有属性
#include<iostream>
using namespace std;
class Home;// 前向声明 Myfriend 类
class Myfriend {
public:
void PlayinBedroom(Home& home);
void Eatindinningroom(Home& home);
};
class Home {
private:
string bedroom;
string dinningroom;
public:
string sittingroom;
Home() {
bedroom = "bedroom";
dinningroom = "dinning room";
}
friend void CleanMyhome(Home &home) {
cout << "友元全局函数访问" << home.bedroom << endl;
}
//成员函数做友元函数
friend void Myfriend::PlayinBedroom(Home& home); //必须把函数内容写在类外面
friend void Myfriend::Eatindinningroom(Home& home);//类内只做声明
};
void Myfriend::PlayinBedroom(Home& home) {
std::cout << "我的朋友正在" << home.bedroom << "里玩" << std::endl;
}
void Myfriend::Eatindinningroom(Home& home) {
std::cout << "我的朋友正在" << home.dinningroom << "里吃饭" << std::endl;
}
int main() {
Home myHome;
CleanMyhome(myHome); // 调用全局友元函数
Myfriend myFriend;
myFriend.PlayinBedroom(myHome); // 调用 Myfriend 的成员函数作为友元函数
myFriend.Eatindinningroom(myHome); // 调用 Myfriend 的成员函数作为友元函数
return 0;
}
[友元类注意]
1.友元关系不能被继承。
2.友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。
练习题
请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,再增加根据输入调台功能。
首先我们要写一下电视的功能
class TV {
friend class Remote;
private:
int mState; //电视状态,开机,还是关机
int mVolume; //电视机音量
int mChannel; //电视频道
public:
enum {On,Off};
enum {minVol, maxVol = 100};
enum{ minChannel = 0, maxChannel = 255};
TV() {
mState = Off;
mVolume = minVol;
mChannel = minChannel;
}
void TurnOnorOff() {
this->mState = (this->mState == Off ? On : Off);
}
//调高音量
void VolumeUp() {
if (this->mVolume >= maxVol) {
return;
}
this->mVolume++;
}
void VolumeDown() {
if (this->mVolume == minVol) {
return;
}
this->mVolume--;
}
//更换电视频道
void ChannelUp() {
if (this->mChannel >= maxChannel) {
return;
}
this->mChannel++;
}
void ChannelDown() {
if (this->mChannel <= minChannel) {
return;
}
this->mChannel--;
}
//展示当前电视状态信息
void ShowTeleState() {
cout << "当前电视" << (mState == On ? "已开机":"已关机") << endl;
if (mState == On) {
cout << "当前音量:" << mVolume << endl;
cout << "当前频道:" << mChannel << endl;
}
cout << "-------------" << endl;
}
class Remote {
private:
TV tv;
public:
Remote(TV& tv) {
this->tv = tv;
}
void OnOrOff() {
tv.TurnOnorOff();
}
//调高音量
void VolumeUp() {
tv.VolumeUp();
}
//调低音量
void VolumeDown() {
tv.VolumeDown();
}
//更换电视频道
void ChannelUp() {
tv.ChannelUp();
}
void ChannelDown() {
tv.ChannelDown();
}
//设置频道 遥控新增功能
void setChannel(int chan) {
if (chan < tv.minChannel || chan > tv.maxChannel) {
return;
}
tv.mChannel = chan;
}
//展示电视信息
void showTV() {
tv.ShowTeleState();
}
};
//直接操作电视
void test01() {
TV television;
television.ShowTeleState();
television.TurnOnorOff(); //开机
television.VolumeUp(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.ChannelUp(); //频道+1
television.ChannelUp(); //频道+1
television.ShowTeleState();
}//通过遥控操作电视
void test02() {
//创建电视
TV television;
//创建遥控
Remote remote(television);
remote.OnOrOff();
remote.ChannelUp();//频道+1
remote.ChannelUp();//频道+1
remote.ChannelUp();//频道+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.showTV();
}
本文来自博客园,作者:ivanlee717,转载请注明原文链接:https://www.cnblogs.com/ivanlee717/p/18025808