从const对象访问非const方法

时间:2019-11-26 16:28:38

标签: c++ inheritance const

我有一个C ++示例,我尝试在通过const getter访问的类成员上设置属性。

#include <iostream>

struct prop
{
    prop() : m_val {0} {}
    int val() const { return m_val; }
    void set_val(int v) { m_val = v; }
private:
    int m_val;
};

struct base
{
    virtual ~base() = default;
    virtual prop property() const = 0;
    virtual void set_property(prop p) = 0;
};

struct derived : public base
{
    derived() : m_prop {prop {}} {}
    prop property() const { return m_prop; }
    void set_property(prop p) { m_prop = p; }
private:
    prop m_prop;
};

int main()
{
    base *d1 = new derived();
    d1->property().set_val(2);
    // prints 0
    std::cout << "property val: " << d1->property().val() << '\n';
    delete d1;

    base *d2 = new derived();
    auto p = d2->property();
    p.set_val(2);
    d2->set_property(p);
    // prints 2
    std::cout << "property val: " << d2->property().val() << '\n';
    delete d2;

    return 0;
}

我希望这会给我d1->property().set_val(2);一个错误,因为property()方法是const,应该给我一个const prop对象,它没有{{1 }} 方法。但这编译时没有任何错误,set_val行实际上并未更改d1->property().set_val(2);,如val行所示。有人可以解释我所缺少的吗?

编辑:我现在了解cout返回非const和按值返回的问题,以及为什么它不会产生编译器错误且不会更改property()。在我的用例中,最好的解决方案是使d1的返回值为property

4 个答案:

答案 0 :(得分:4)

  

d1->property().set_val(2);实际上并没有更改val

因为property()按值返回,这意味着property()返回的是一个临时对象,它是从数据成员m_prop复制而来的。然后在立即销毁的临时对象上调用set_val

  

因为property()方法是const,应该给我一个const prop对象

不。您将返回类型声明为prop,然后它将返回非常量prop。在const property()中,数据成员m_prop变为const,并将其复制到返回的非const对象中。返回类型不会成为const

我认为您应该将返回类型更改为const prop&(在basederived类中)。然后,您将得到预期的错误。例如

const prop& property() const { return m_prop; }

答案 1 :(得分:3)

property返回m_prop副本,它是可修改的值,尽管是临时值。因此,您无需对dl进行任何更改,并且打印时的值仍将是原始值。

答案 2 :(得分:2)

该方法为const只是意味着调用它不会使您调用它的对象发生变异。

从方法中返回的对象(按值)是一个全新的对象,您可以根据需要对其进行操作。它与您从中获得对象的对象无关(除了是获取getter所返回内容的副本),也不与您获取该对象的函数的const性质有关。

答案 3 :(得分:2)

如果您希望您的property()成员函数返回一个const prop对象,请指定这样做:

struct base{
    virtual const prop property() const=0;
};

按现状,您将获得一个非const prop对象,它是属性的副本。您可以快乐地设置该对象的值,但不会影响存储的属性值。