参看《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设置为指向常量的指针。有助于提高函数的灵活性。
这里提高灵活性就是说:不管常量对象,还是非常量对象,都可以调用常量成员函数。而普通函数,只能被非常量对象调用。