【问题标题】:Are const data member allowed to change outside the class?是否允许 const 数据成员在类外更改?
【发布时间】:2020-03-25 19:21:56
【问题描述】:

如果一个类有一个 const 引用数据成员碰巧在该类范围之外发生变化,这是未定义的行为吗?

例如,让我们考虑以下 C++ 代码:

#include <iostream>

class A {
  int x;
public:
  A(int x): x(x){}
  void change(int y){
    x = y;
  }
  friend std::ostream & operator << (std::ostream & os, const A & a){
    os << a.x;
    return os;
  }
};

class B {
  const A & a;
public:
  B(const A & a) : a(a) {}
  friend std::ostream & operator << (std::ostream & os, const B & b){
    os << b.a;
    return os;
  }
};

int main(){
  A a(1);
  B b(a);
  std::cout << a << std::endl;
  std::cout << b << std::endl;
  a.change(2);
  std::cout << a << std::endl;
  std::cout << b << std::endl;
}

我的编译器能够正确执行它,并且调试器指出 B::a 的 x 已更改。

感谢您的帮助!

【问题讨论】:

  • const T &amp; 并不意味着它指的是T,即const。这意味着它是对 T 的引用,并且不允许您使用该引用来更改该对象。和const T *是一样的。
  • @FrançoisAndrieux 感谢您的回复!我以为是这样,但由于我刚刚了解了未定义的行为,现在我有一种妄想症,首先要仔细检查所有内容!再次感谢!
  • 对 UB 偏执基本上是唯一安全的立场。如果你有任何疑问,确定是正确的。

标签: c++ reference constants


【解决方案1】:

这不是未定义的行为。 const 引用是B 的成员,仅意味着B 的实例不能通过该引用更改它。但是,因为它是一个引用,所以其他东西可能会改变它——包括B 的其他成员,它们有自己的非const 引用到A 的同一实例。

比较添加成员 c 到您现有的 B 类,并注意我们正在通过非 const 引用在 B::changeA() 内成功更改它,也从 @987654333 中的 C::change() 向下更改@:

#include <iostream>

class A {
  int x;
public:
  A(int x): x(x){}
  void change(int y){
    x = y;
  }
  friend std::ostream & operator << (std::ostream & os, const A & a){
    os << a.x;
    return os;
  }
};

class C
{
    A& a;
public:
    C(A& a) : a{a} {}
    void change(int y) { a.change(y); }
};

class B {
  const A & a;
  C& c;
public:
  B(const A & a, C& c) : a(a), c{c} {}
  friend std::ostream & operator << (std::ostream & os, const B & b){
    os << b.a;
    return os;
  }
  void changeA(int y) { c.change(y); }
};

int main(){
  A a(1);
  C c(a);
  B b(a,c);

  std::cout << a << ' ' << b << '\n';

  a.change(2);
  std::cout << a << ' ' << b << '\n';

  b.changeA(3);
  std::cout << a << ' ' << b << '\n';

  c.change(4);
  std::cout << a << ' ' << b << '\n';
}

看到它在 Coliru 上实时运行,它会打印:

1 1
2 2
3 3
4 4

【讨论】:

  • 感谢您的回复和示例!说清楚了!
【解决方案2】:

您不能使用对对象的常量引用来更改对象,但如果对象不是常量或使用对对象的非常量引用,您可以更改对象本身。

考虑以下演示程序。

#include <iostream>

int main() 
{
    int x = 10;

    int &rx = x;
    const int &crx = x;

    std::cout << "rx = " << rx << '\n';
    std::cout << "crx = " << crx << '\n';

    rx = 20;

    std::cout << "rx = " << rx << '\n';
    std::cout << "crx = " << crx << '\n';

    return 0;
}

它的输出是

rx = 10
crx = 10
rx = 20
crx = 20

这与使用指向常量数据的指针相同。例如

#include <iostream>

int main() 
{
    int x = 10;

    int *px = &x;
    const int *cpx = &x;

    std::cout << "*px = " << *px << '\n';
    std::cout << "*cpx = " << *cpx << '\n';

    *px = 20;

    std::cout << "*px = " << *px << '\n';
    std::cout << "*cpx = " << *cpx << '\n';

    return 0;
}

【讨论】:

  • 感谢您的回复!我想现在我理解得更好了!
猜你喜欢
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多