类成员函数学习——隐藏的this指针 + const修饰类成员函数

类的成员变量存放在栈上,而类的成员函数是放在代码区的

类和对象——类的定义、类的封装、类的存储方式_abs(ln(1+NaN))的博客-CSDN博客https://blog.csdn.net/challenglistic/article/details/123585545这个在类的存储方式这部分已经说明过了,那我就以博客中的Person类为例


目录

一、提出疑问:公共区的成员函数如何区分不同对象的调用?

1、案例介绍

 2、提出疑问

3、解决疑问

二、隐藏的this指针:流插入'<<'、流提取'>>'运算符重载实现

1、流插入 ' << '

(1) 注意事项

 (2) 代码实现 + 测试

2、流提取 ' >> '

三、const修饰成员函数


一、提出疑问:公共区的成员函数如何区分不同对象的调用?

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;
}

 涉及到的 += 运算符重载可以参考

string类的模拟实现(五)—— 运算符重载_abs(ln(1+NaN))的博客-CSDN博客运算符 += 、 = 、>、[ ] 的重载实现https://blog.csdn.net/challenglistic/article/details/123975612?spm=1001.2014.3001.5501代码测试:

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指向的内容,也就是私有成员变量

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值