如果我有类成员函数:
bar* foo::get_value() const
{
return &_value;
}
编译器会抱怨
无法使用类型为const bar *
的rvalue初始化bar *类型的变量
_value在课程中不是const
。
如果我有这个功能:
bar* foo::get_value() const
{
return const_cast<bar *>(&_value);
}
它运作得很好。
我认为声明成员函数常量意味着您承诺不修改类的内部内容,但操作&
似乎在const
成员函数中返回一个常量指针。这是为什么?
答案 0 :(得分:5)
当您声明函数const
时,您说这是一个在对象的非const和const实例上都允许的函数。因为它可以在const
实例上调用,所以该函数不应该改变该对象。当您向内部对象返回非const引用时,您将为调用者提供一种间接改变对象内部状态的方法。要解决此问题,请返回一个常量对象。
换句话说,而不是:
Bar* Foo::GetBar() const
执行:
const Bar* Foo::GetBar() const
或者,更好的是:
const Bar& Foo::GetBar() const
正如您所观察到的,const_cast
允许您破坏对象的常量。通常,您应该避免使用const_cast
;使用它是一种代码气味,它破坏了预期的const
保证。
答案 1 :(得分:1)
问题是getter函数的返回类型。您将返回bar*
而不是const bar*
。前者允许get_value
函数的调用者修改对象。但是,您明确禁止将_value
声明为const
。
您可以使用const_cast
绕过它,但它不正确。这就像告诉编译器“相信我,我知道我在做什么”,但在这种情况下,你没有。您无法控制调用代码将对该对象执行的操作。如果他们试图修改它 - bam,未定义的行为。
让自己变得简单,只需让getter返回const bar*
:
const bar* foo::get_value() const
{
return &_value;
}
请注意,编译器错误消息实质上告诉您需要对代码进行更改。
答案 2 :(得分:1)
const成员函数仅适用于const对象。使用const对象,您无法更改其成员变量。这就是为什么编译器不允许你创建一个指向const对象的成员变量的非const指针。
答案 3 :(得分:1)
当一个对象实例被声明为const
时,它被视为所有成员变量也是const
- 也就是说,除了使用关键字{{'声明的成员之外1}}。
因此,从理论上讲,您可以将mutable
声明为_value
,这至少会比mutable
略微优于const_cast<>
。但它仍然不理想。正确的方法是提供两个重载:
const bar* foo::get_value() const
{
return _value;
}
bar* foo::get_value()
{
return _value;
}
(更好的是使用引用或智能指针而不是原始指针)。