const方法使用引用修改对象

时间:2018-06-13 11:31:52

标签: c++

以下代码调用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能够修改对象。

5 个答案:

答案 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。但是,您的方法不会(直接)修改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.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;
}