在下面的代码中, const 类方法B调用了其成员的非 const 方法A &a_ref,这似乎与const限定符的逻辑相矛盾(理论上,代码不应该编译)。为什么会发生这种情况?
最低代码:
#include <iostream>
class A
{
public:
void NonConstHello() /*const*/
{
std::cout << "non const Hello from A!" << std::endl;
}
};
class B
{
public:
A &a_ref;
explicit B(A &a) : a_ref(a) {}
void ConstHello() const /*const method*/
{
a_ref.NonConstHello(); // calls non-const method for his member???
std::cout << " const Hello from B!" << std::endl;
}
};
int main()
{
A a;
B b(a);
b.ConstHello();
return 0;
}
结论:
non const Hello from A!
const Hello from B!
在上面的代码中,没有调用 const 对象上的非常量方法
问题中的代码等效于以下内容:
此外,它在功能上和链接的定义上都是等价的。
让我们弄清楚
const-qualifier 发生了什么。类方法的常量性
B意味着它的所有成员都变成常量,就像值一样,也就是说,指针变成常量,得到一个类型A * const(而不是const A*!)。这意味着我们不能从该方法将指针更改为地址,但可以合法地更改数据,对非常量方法的调用不是在类成员上发生,而是在其取消引用的结果上发生。
解引用运算符是 const (它不能更改地址)并返回对我们合法应用非常量方法的对象的非常量引用。
让我们回到带有链接的原始示例。
现在一切都清楚了。如果非常粗略,引用是“在必要时隐式转换为对象的指针”。调用链接上的方法实际上并不是调用链接上的方法,而是调用位于相应地址的对象上的方法。
方法的常量性
B禁止我们更改作为链接的成员(即更改其地址),但不禁止更改链接指向我们的数据,我们通过调用非常量方法。粗略地说,
a_ref在常量类方法中,B它有一个类型 notconst A&,但是A & const(公平地说,我们注意到引用无论如何都不能改变,它只初始化一次,它的地址不再改变,实际上它是,因为地址是不变的)。