类的const成员函数(4)

时间:2022-09-07 23:47:49

参看《c++primer》P231内容,之前有点云里雾里,反复看不甚清晰。写了个实际例子方才搞清,记下。

定义一个类A:

class A {
public:
A() = default;
A(int tmp) : num(tmp) {}
~A() = default;
void print() { cout << a; }
private:
int num = 0;
};

然后我们测试如下:

A a(3);
a.print();

生成一个A类的对象a,实参为3。编译器调用对应的构造函数,将a.num赋值为3。然后调用普通成员函数print打印出值。我们知道,调用成员函数时,实际上会把该对象的this指针隐式传进去。也就是说函数print的实际形式为:

A::print(A * const this)
{
cout << this->num;
}

注意this是个常量指针,因为它的目的总是指着这个对象,不允许修改this中保存的地址。于是不同的对象,都会调用各自的num。

A a(3);
a.print(); // 打印3
A b(4);
b.print(); // 打印4

如果有下面代码:

const A c(12);
c.print();

我们定义了个常量对象。此时编译器会报错。提示“不兼容的类型限定符”。为何有这个错误?按照上述分析,调用print时会传入该对象的this指针,因为c为常量对象,所以其this指针类型为

const A * const this

而print的实际形式为:

A::print(A * const this)
{
cout << this->num;
}

问题就在这里。我们不能将普通指针变量绑定到指向常量的指针上。即:

A * const this = const A * const this   //error

那么如何解决呢?我们可以将this指针转化为const型的即可。但this的传递是隐式的,c++中允许把const关键字放在成员函数的参数列表后面,即可将this转化为const型。具体来说

class A {
...
void print() const { cout << a; }
...
};

则print函数的实际形式为:

A::print(const A * const this)
{
cout << this->num;
}

再次运行下面代码即正确。

const A c(12);
c.print();

此时,print因为加了const关键字称为:常量成员函数。由此可以理解《c++ primer》P232页的note:

常量对象,常量对象的引用或指针,只能调用常量成员函数。

以及这段话:

默认情况下,this的类型是指向类类型的非常量版本的常量指针。尽管this是隐式的,仍然遵守初始化规则。默认下我们不能将this绑定到一个常量对象上。则我们也就不能在一个常量对象上调用普通成员函数。

如果函数体内不会改变this所指的对象,应把this设置为指向常量的指针。有助于提高函数的灵活性。

这里提高灵活性就是说:不管常量对象,还是非常量对象,都可以调用常量成员函数。而普通函数,只能被非常量对象调用。