类的成员变量存放在栈上,而类的成员函数是放在代码区的
类和对象——类的定义、类的封装、类的存储方式_abs(ln(1+NaN))的博客-CSDN博客https://blog.csdn.net/challenglistic/article/details/123585545这个在类的存储方式这部分已经说明过了,那我就以博客中的Person类为例
目录
二、隐藏的this指针:流插入'<<'、流提取'>>'运算符重载实现
一、提出疑问:公共区的成员函数如何区分不同对象的调用?
1、案例介绍
Person类:
class Person
{
public:
Person() {}
Person(int age)
{
_age = age;
}
void PrintPersonInfo()
{
cout << "此人的年龄是:" << _age << endl;
}
private:
int _age;
char* _name;
};
测试代码:
int main()
{
Person p1(10);
p1.PrintPersonInfo();
Person p2(20);
p2.PrintPersonInfo();
return 0;
}
2、提出疑问
既然成员函数 PrintPersonInfo 在代码区,也就是公共区
为什么不同的对象,打印了不同的结果,明明没有传递任何参数
-》答案是 在编译过程中,编译器会为成员函数自动加上一个参数,这个参数是 this指针
3、解决疑问
类成员函数 PrintPersonInfo() 隐藏了一个参数 this,this的地址不可以修改,但是指向的内容可以修改
在编译的时候,编译器会自动补上,变成
void PrintPersonInfo(Person* const this) //参数this的地址无法被修改,指向的内容也无法被修改
{
cout << "此人的年龄是:" << this->_age << endl;
}
在传递参数的时候,表面上是
Person p1(10);
p1.PrintPersonInfo();
实际上编译器在编译的时候,会自动补上一个对象地址
Person p1(10);
p1.PrintPersonInfo(&p1);
有了对象作为区分,不同的对象调用就会传递不同的地址
打印的结果也就不同
注意:不要想着自己加这个参数,这个参数编译器会自动加上去,无需我们操心,我们只需要知道这个参数确实存在即可
二、隐藏的this指针:流插入'<<'、流提取'>>'运算符重载实现
上面的结论能够解释:运算符的重载实现时为什么可以省略参数
1、流插入 ' << '
(1) 注意事项
以cout为例,流插入的基本使用如下
该运算符有两个操作数,且该运算符的左操作数必须是 输出流ostream
cout << "hello,world" ;
注意一:流插入的声明和定义,必须要放在类外!!!
如果放在类内
ostream& operator<<(ostream& out, const MyString& s);
那么编译的时候就会变成
ostream& operator<<(const MyString* const this ,ostream& out, const MyString& s);
就会变成三操作数,而且左操作数必须是 MyString对象的地址
这是不符合要求的,我们的左操作数必须是 ostream 类型!!
注意二:将该函数声明为MyString类的友元函数
当前函数不属于MyString类,无法调用该类的私有成员
所以,必须要把当前函数 声明为MyString类的友元函数
这就说明,MyString认同 operator<< 函数是朋友,既然是朋友就可以访问我的私有成员
(2) 代码实现 + 测试
了解了上面两点注意事项,下面就可以开始实现了
实现起来也很简单
我们在 .h文件中声明,但是要放在类外
ostream& operator<<(ostream& out, const MyString& s);
在.cpp文件中定义
ostream& operator<<(ostream& out, const MyString& s)
{
out << s._str; //ostream内部本来就定义了 运算符<<,这里我们可以直接使用
return out;
}
代码测试:
cout 就是 ostream类型 ,所以我们使用cout作为左操作数
int main() {
MyString s1("hello,world");
cout << s1 << endl;
return 0;
}
2、流提取 ' >> '
注意事项同流插入运算符,这里就不再赘述,下面直接介绍代码实现
另外需要注意的是 s的成员变量会发生变化,所以不能const修饰
我们要模仿的是cin,cin遇到空格或者'\n'就会停止读取
cin >> s; //遇到空格或者\n就停止读取
函数声明如下
istream& operator<<(istream& in, MyString& s); //s的成员变量会发生变化,所以不能const修饰
函数定义如下
istream& operator<<(istream& in, MyString& s)
{
char ch = in.get(); //获取第一个字符
while (ch != ' ' && ch != '\n')
{
s += ch; //添加新字符
ch = in.get(); //获取下一个字符
}
return in;
}
涉及到的 += 运算符重载可以参考
int main() {
MyString s1("hello,world");
cin >> s1;
cout << s1;
return 0;
}
三、const修饰成员函数
第一部分说到,每个成员函数都有一个隐藏的参数 ,即当前类的 this指针
void PrintPersonInfo(Person* const this)
{
//...
}
但是一旦加了const修饰,就像下面这样
void PrintPersonInfo(Person* const this) const
{
//...
}
编译的时候,会变成下面这样
void PrintPersonInfo(const Person* const this)
{
//...
}
这样的话,我们就无法修改this指向的内容,也就是私有成员变量