如何正确返回对类成员的引用?

Dim*_*ris 11 c++

class Foo {
    protected:
    QPoint& bar() const;

    private:
    QPoint m_bar;
};

QPoint& Foo::bar() const {
    return m_bar;
}
Run Code Online (Sandbox Code Playgroud)

我收到了这个错误:

错误:从'const QPoint'类型的表达式初始化'QPoint&'类型的引用无效

但是,如果我将其更改为:

QPoint& Foo::bar() const {
    return (QPoint&) m_bar;
}
Run Code Online (Sandbox Code Playgroud)

1)我不明白为什么编译器说我的QPoint是const.

2)将演员留在那里可以吗?

sbi*_*sbi 22

在类的非const成员函数中Foo,this指针是类型的Foo* const- 也就是说,指针是const,但不是它指向的实例.但是,在const成员函数中,this指针属于该类型const Foo* const.这意味着它指向的对象也是不变的.

因此,在您的示例中,当您使用this->m_bar(其中m_bar只是简短形式)时,则m_bar是常量对象的成员 - 这就是为什么您不能将其作为非const引用返回的原因.

这从设计POV实际上是有意义的:如果该Foo对象是一个常量对象,并且允许您Foo::bar为常量对象调用,那么,如果这将返回一些非const引用,你可以使用一些内部结构,那么你将是能够改变常量对象的状态.

现在你必须看看你的设计并问问自己你是如何到达这一点的,以及你的实际目的是什么.如果该m_bar成员实际上不是对象状态的一部分(例如,它仅用于调试目的),那么您可以考虑制作它mutable.如果它是对象状态的一部分,那么你必须问自己为什么要对常量对象的某些内部数据返回非const引用.要么使成员函数非const,要么返回const引用,或者重载成员函数:

class Foo {
public:
  const QPoint& bar() const {return m_bar;}
        QPoint& bar()       {return m_bar;}
  // ...
};
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.我认为const函数限定符只是为了保证函数本身不会修改对象.我希望m_bar可以修改,所以我删除了限定符. (2认同)

RC.*_*RC. 5

你试图做的是一个禁忌。您不想从 bar 函数返回 QPoint & 因为这会破坏封装,因为调用者现在可以从 QPoint 下方修改 m_bar。(幸运的是,您将函数声明为 const 否则您不会在此处收到错误,并且您仍然会破坏封装)。

在这种情况下你想要的是

const QPoint &Foo::bar() const
{
    return m_bar;
}
Run Code Online (Sandbox Code Playgroud)

根据用户评论编辑:

恕我直言,通过添加setXtoFoo而不是从真正应该是 const 的访问器函数返回的非常量引用调用非常量函数可以更好地解决这个问题。重载访问器函数以删除 const 只是为真正的问题提供了一个创可贴,只是隐藏了封装被破坏的事实。添加setX到 Foo 修复了封装问题,并通过返回对私有数据的非常量引用来堵塞您正在创建的泄漏接口。

例如,如果您放入foo.bar().setX(100);应用程序的许多部分,然后将 的类型更改为QPoint未实现的类型,setX或者只是重命名函数setX以说明setPointX您有问题 b/c,那么您现在必须绕过重命名/重构所有这些电话。在 Foo 上创建 setX 使代码更容易调用 foo.setX(100)vs foo.bar().setX(100),是 const 正确的,并且封装了您的数据。如果您将 QPoint 更改为 Foo 中的 2 个 x 和 y 坐标,则您的班级以外的任何内容都不必更改 b/c,您将获得良好的封装。