以下代码调用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编译,没有警告。
代码合法吗?
当从const
方法调用时,calc
方法non-const
能够修改对象。
答案 0 :(得分:7)
const
限定符适用于*this
实例。
在calc()
中,this
是指向const A
的指针,但参数j
由非const引用获取,因此这是完全标准的行为。 / p>
现在,如果您在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引用所采用的参数)
答案 1 :(得分:5)
不确定。标记方法const
只会使*this
const
,即函数承诺不会通过this
进行修改来修改对象。
仍然可以通过其他方式修改对象(假设它们也没有标记const
,例如示例中的int& j
。)
答案 2 :(得分:1)
您的代码没有任何问题。声明方法const
仅仅意味着this
是const。但是,您的方法不会(直接)修改this
或this
的任何成员。考虑这个人为的,尽管是正确的例子:
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.modify_const(f);
上的const f
调用将因参数作为非const传递而失败。
答案 3 :(得分:1)
请记住,拥有一个&#34; const指针&#34;比如const Thing*
或&#34; const引用&#34;像const Thing&
一样并不意味着当你有指针/引用时,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
看起来好像必须始终在&#34;之前打印相同的值&#34; &#34;&#34;&#34;&#34;线。但是,如果有人将相同的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
,这意味着您无法更改A
对象使用this
指针。但是仍然可以有其他方法来改变它,比如你有一个int& j
对非const对象的引用。如果恰好j
引用*this
的子对象,则修改j
是修改*this
子对象的有效方法。这类似于上面我的f1
示例,其中arg1
无法用于更改引用的int
,但arg2
可以,如果它们引用相同int
,这意味着arg1
已更改。
当变量定义并且首先使用const
限定符时,情况略有不同。如果我们写
const A a(3);
然后我们得到一个保证(除了在构造函数和析构函数中),对象不能以任何方式进行更改。该语言通常会阻止您意外尝试,例如使用a.set1()
,但即使您尝试const_cast
技巧,任何实际更改都将是未定义的行为。
答案 4 :(得分:0)
只是表明你永远不会安全。 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;
}