【问题标题】:Why can reference members be modified by const member functions?为什么引用成员可以被const成员函数修改?
【发布时间】:2014-05-02 20:57:28
【问题描述】:

以下内容将compile,即使 const 成员函数会修改成员的值。怎么会?

#include <iostream>

struct foo
{
    std::string &str;
    foo(std::string &other) : str(other) {}

    void operator()(std::string &some) const
    {
        str += some;
    }
};

int main()
{
    std::string ext("Hello");
    foo a{ ext };

    std::string more(" world!");
    a(more);

    cout << a.str;
    return 0;
}

【问题讨论】:

  • 修改成员所指的内容,不修改成员。
  • 因为它不会修改引用本身。应用+= 运算符后,引用没有改变,只有内部字符串内容会改变(在字符串的上下文中,this 仍然相同)。
  • 用 std::string* 代替 & 试试,你会看到同样的结果。
  • 它被称为按位 const,这是 C++ 强制执行的,而不是逻辑 const。见this questionthis one

标签: c++


【解决方案1】:

将引用视为经典指针:

#include <iostream>

struct foo
{
    std::string * const str; // is the same as std::string &str
    foo(std::string &other) : str(&other) {}

    void operator()(std::string &some) const
    {
        *str += some;
    }
};

int main()
{
    std::string ext("Hello");
    foo a{ ext };

    std::string more(" world!");
    a(more);

    cout << a.str;
    return 0;
}

你会看到指针没有改变,只有它指向的值会改变。

【讨论】:

    【解决方案2】:

    类成员函数的const 限定符表示该成员函数(例如,foo::operator() const)不能从客户端的角度改变对象的状态(即,它是抽象的状态)。这与说对象的原始位不会改变并不完全相同。

    C++ 编译器禁止将对象视为原始位,除非它们可以解析 the problem of aliasing。在您的情况下,编译器不能。这是因为存在非常量别名(即std::string &amp;str),因此对象的状态是可修改的。

    也就是说,在对象a 上调用operator() 不会改变a 的状态(即,虽然ext 已经改变,但str 仍然是ext 的别名)。

    上面还解释了为什么用指向常量的指针(即std::string * const str)指向一个对象并不能保证该对象不会被修改。它只保证对象不会通过该指针发生变化。

    【讨论】:

      猜你喜欢
      • 2017-10-11
      • 2018-09-06
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      相关资源
      最近更新 更多