【C++】const成员函数+取地址重载(默认成员函数)

举报
YIN_尹 发表于 2023/08/21 18:30:20 2023/08/21
【摘要】 const成员函数我们来看这样一个类:class A{public: void Print() { cout << _a << endl; }private: int _a = 10;};然后:int main(){ A a; a.Print(); return 0;}定义一个对象a,并调用成员函数Print。没有什么问题。那这样呢?加...

const成员函数

我们来看这样一个类:

class A
{
public:
    void Print()
    {
        cout << _a << endl;
    }
private:
    int _a = 10;
};

然后:

int main()
{
    A a;
    a.Print();
    return 0;
}

定义一个对象a,并调用成员函数Print。

f2466beea279447f8bd92625f69aabef.png

没有什么问题。

那这样呢?

50488cb2c7194c8a97f2c1b9bf9533ac.png

加一个const修饰对象a。

8c5a1ed7f2e242f8979e2ae46b8999e6.png

然后我们发现调用Print就出错了。


那为什么呢?


其实呢是因为这里存在了一个权限放大的问题。

这也是我们之前学习过的:对于引用,还有指针来说,对它们进行赋值和初始化时,权限可以缩小,但不能放大。

我们来分析一下:

对于我们的成员函数Print,虽然看起来没有参数,但是是不是有一个隐藏参数,就是我们熟悉的this指针嘛。

那this指针的类型是啥?

this指针的类型:类类型* const

那对于当前这个类来说就是A* const this,const 修饰的是指针this,即指针this不能被修改,但this指向的内容可以被修改。

那我们传过来的参数是啥,是调用函数的对象的地址,即a的地址,但我们的对象a是const修饰的,所以传过来的地址的是const A* &a,const修饰的是该地址指向的内容,即对象a不能被修改。

那这样的话,传给this,this可以修改其指向的内容即对象a,所以就是权限放大了。

所以这里报错了。


那怎么解决呢?


🆗,如果我们可以把this指针的类型也变成const A*是不是就可以了啊。

但是this指针的类型是我们想改变就能改变的吗?

this指针是类成员函数中的一个隐藏参数,我们是没法直接改变它的。

那就没有办法了吗?

办法肯定是有的:cb56b0df3e2c436ab34737d46e77174a.png

我们只需在对应成员函数的括号后面加一个const 就行了。

这就是我们要学的const成员函数:

const修饰的“成员函数”称之为const成员函数。

const修饰类成员函数,实际修饰的是*this,这样this指向的对象将不能被修改。


9c828125108249669be1d1b7fa7c9b94.png

那这样this指针的类型就也变成了const A*了,这样就可以传了。


0d548dc8fe0045e1ad09bd84d9b83967.png

但是我们平时定义一个对象好像一般也不会在前面加一个const,那这个用处是不是不大啊?

🆗,虽然定义对象时我们一般不加const,但是我们是不是可能经常会这样搞:

void Func(const A& x)
{
    x.Print();
}

首先这里传引用与传值相比减少拷贝,然后如果我们不想对象被改变的话,不是一般会加一个const嘛。

那当前这种情况:

class A
{
public:
    void Print()
    {
        cout << _a << endl;
    }
private:
    int _a = 10;
};
void Func(const A& x)
{
    x.Print();
}
int main()
{
    A a;
    Func(a);
    return 0;
}

x是a的引用(别名),a没有被const修饰,然后在Func里,x是被cosnt修饰的,x去调用Print,这里是不是也是权限放大了。

1de4094b6e4d40dc9d4d51f1a24d92f7.png

089c4297970b4c6dac789974783a4116.png

那这是不是跟我们开始讲的那个例子一样啊,怎么解决?
把Print变成const成员函数就行了:

63b1bf9f3e6646bdab0ab36299e7c13e.png像这种情况其实还是比较常见的。


所以说:


对于类的成员函数,如果在成员函数内部不需要改变调用它的对象,最好呢都可以把它写成const成员函数。

另外,如果const成员函数的声明和定义是分开的,声明和定义都要加const。


 取地址及const取地址操作符重载

类的6个成员函数呢,比较重要的前4个我已经学完了,最后还剩两个。


我们一起来看一下:


那剩下的两个默认成员函数呢都是取地址重载,包括对普通对象的取地址和对const对象取地址。

这两个默认成员函数呢一般不需要我们自己去实现,编译器会自动生成,绝大多数情况下我们用编译器自动生成的就行了。


我们可以试一下:


对普通对象取地址7891776153ff43b296c1346f7b266526.png

对const对象取地址

9ab5d58cc848411fab4edf418c70521f.png

所以这两个默认成员函数一般不需要我们自己写,用编译器默认生成的取地址的重载即可

但是,如果你想自己去重载一下的话当然也是可以的:


9e643bb1eddc40739142cf7292efde11.png

13398d2776ff41f1bbfb40f2a06087a2.png你可以自己指定一个地址返回。

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

🆗,那我们这篇文章的内容就先到这里,欢迎大家指正!!!

e172fe2629c048b9ab2f75d8eb9db931.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。