const 方法使用引用修改对象

const method modifies object using reference

本文关键字:修改 对象 引用 方法 const      更新时间:2023-10-16

下面的代码调用一个const方法,该方法传递对成员的引用,然后修改该成员。

#include <iostream>
struct A {
int i;
A(int _x) : i(_x) { }
void calc(int& j, const int value) const { j = value; }
void set1() { calc(i, 1); }
};
int main()
{
A a(3);
std::cout << a.i << std::endl;
a.set1();
std::cout << a.i << std::endl;
return 0;
}

代码使用 gcc 6.4.0 和 clang 5.0.2 编译,没有警告。

代码合法吗? 从non-const方法调用时,const方法calc能够修改对象。

成员函数上的const限定符适用于*this实例。

calc()中,this是指向常量A的指针,但是参数j是由非常量引用获取的,所以这是完全标准的行为。

现在,如果您在calc中尝试分配给this->i,则代码将无法编译。

void A::calc(const int value) const
{
i = value; // Compilation error here: i is a data member of a const instance
}

同样,如果set1成为 const 成员函数,则代码将不会编译(因为它会尝试将this->i绑定到非 const 引用获取的参数(

当然。标记方法const只是*thisconst,即函数承诺不会通过写入this修改对象。

仍然可以通过其他方式修改对象(假设它们也没有标记为const,例如示例中的int& j(。

请记住,拥有像const Thing*这样的"const 指针"或像const Thing&这样的"const 引用"并不意味着在拥有指针/引用时不能更改 const 限定的对象。 这仅意味着您不能使用该特定指针/引用作为更改它的一种方式。但是可能还有其他名称、指针或引用允许更改它。

举几个例子:

void f1(const int& arg1, int& arg2) {
std::cout << "arg1 before: " << arg1 << "n";
arg2 = 4;
std::cout << "arg1 after: " << arg1 << "n"; // same thing?
}

f1看起来好像它必须始终在"之前"和"之后"行中打印相同的值。 但如果有人将相同的int反对传递给两个参数,则不会:

void call_f1() {
int n = 7;
f1(n, n); // Prints before 7, after 4!
}

或者,如果函数调用介于 const 引用的两种使用之间,则类似地可以以某种方式更改变量:

void something_else();
void f2(const int& arg) {
std::cout << "arg before: " << arg << "n";
something_else();
std::cout << "arg after: " << arg << "n";
}
int n = 2;
void something_else() { n = 8; }
void call_f2() {
f2(n); // Prints before 2, after 8!
}

因此,在您的void A::calc(int& j, const int value) const函数中,this指针确实是const A* const,这意味着您无法使用this指针更改A对象。 但是仍然可以有其他方法可以更改它,例如在这里您有一个对非常量对象的int& j引用。 如果碰巧j引用了*this的子对象,则修改j是修改*this子对象的有效方法。 这类似于我上面的f1示例,其中arg1不能用于更改引用的int,但arg2可以,如果它们引用相同的int,这意味着arg1已更改。


当首先使用const限定符定义变量时,情况略有不同。 如果我们写

const A a(3);

然后我们确实得到了一个保证(除了在构造函数和析构函数期间(,对象不能以任何方式更改。 该语言通常会阻止您意外尝试,例如a.set1(),但即使您尝试const_cast技巧,任何实际更改都将是未定义的行为。

你的代码没有错。声明方法const仅意味着this是常量。但是,您的方法不会(直接(修改thisthis的任何成员。 考虑这个人为的,尽管是正确的例子:

struct foo {
int value;
void modify_const(foo& f) const { f.value = 5; }
};
int main() {
foo f;
f.value = 3;
f.modify_const(f);
}

该方法不会修改this,并且参数被声明为非常量,因此在const f上调用f.modify_const(f);将失败,因为参数被传递为非常量。

只是表明你永远不会安全。const限定符并不能保证值永远不会更改。

尝试这样,你可以做一些非常讨厌的事情:

#include <iostream>
class A {
const int i;
void calc(int& j, const int value) const { j = value; }
public:
A(int _x) : i(_x) { }
void set1() const { calc(*const_cast<int*>(&i), 1); }
int getI() const { return i; }
};
int main()
{
const A a(3);
std::cout << a.getI() << std::endl;
a.set1();
std::cout << a.getI() << std::endl;
return 0;
}