我有一个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
。
答案 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&
(在base
和derived
类中)。然后,您将得到预期的错误。例如
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
对象,它是属性的副本。您可以快乐地设置该对象的值,但不会影响存储的属性值。