如果我们有这个类定义
class BusDetails
{
private:
string m_busName;
public:
string BusName() const { return m_busName; }
};
如何更改或使用getter方法,以便将返回值用作左值会产生编译错误?
例如,如果我像
一样使用它int main(void)
{
BusDetails bus;
bus.BusName() = "abc"; // <--- This should give a compiler error
cout << bus.BusName() << endl;
return 0;
}
我没有编译错误,所以显然分配工作正常,但结果并不像预期的那样。
更新:这种行为与内置类型一样正常(例如,如果我将int
作为返回类型而不是编译器在上面的代码行中出错string
)。
答案 0 :(得分:2)
BusName()
被声明为const函数。所以它不能改变成员。
你的函数应该返回string&
而不是const。
string& BusName() { return m_busName; }
另外你可以添加const对象(this
是const):
const string& BusName() const { return m_busName; }
答案 1 :(得分:2)
目前尚不清楚你想要的行为。
如果您希望分配是一个错误,并保留所有
值返回的灵活性(例如,您可以将代码修改为
返回计算值),您可以返回std::string const
。
(这会抑制移动语义,但通常不会
一个大问题。)
如果您希望能够修改“成员”,但仍然想要
保持关于如何实施的灵活性
该类,那么你应该提供一个setter方法。一
约定(不是唯一的)是提供一个getter函数
就像你现在一样(但返回std::string const
),和
提供具有相同名称void
BusName( std::string const& newValue )
的函数来设置值。
(其他约定将使用SetBusName
之类的名称,或返回
旧值,因此客户端代码可以保存和恢复它,或
返回*this
,因此客户端代码可以链接操作:
obj.BusName( "toto" ).SomethingElse( /*...*/ )
。
您还可以提供一个返回引用的非const成员 到一个非常数。但是,如果你这样做,你也可以做 数据成员公开。
最后,您可能会提供一个返回的非const成员
某种代理类,实际上分配给它
调用setter函数,并将其转换为std::string
打电话给吸气鬼。这是迄今为止最灵活的, if 你
想要支持客户的修改,但它也是
最复杂的,所以你可能不想使用它,除非你
需要。
答案 2 :(得分:1)
这就是你所写的预期行为。
您确实会返回m_busName
的副本。因为你没有返回引用。因此,返回变量的临时副本,然后进行分配。 <{1}} operator=
在该副本上被调用。
所以要走的路是"abc"
。但这会给编译器错误。
你有点想要矛盾的事情。你说string& BusName() const { return m_busName; }
,但是你想要返回一个允许改变对象状态的引用。
但是,如果您不保证对象不会更改,您可以删除string BusName() const
并使用
const
或者,如果您想保留string& BusName() { return m_busName; };
const
然而,这应该会给分配带来错误,当然。
功能也是如此。如果你通过引用传递参数,那么它就是一个引用。如果您看到您修改了副本,则必须未通过引用传递它,而是按值传递。
答案 3 :(得分:1)
该函数确实返回一个右值。
问题是std::string::operator=
的作品左边有一个右值。在C ++ 11之前,很难或不可能阻止它工作:在C ++ 11中,它们(相对较晚)添加了通常称为this
的右值引用的内容:重载方法和in-的能力基于对象的右值状态的类运算符。
然而,std::string
没有被修改,可能是没有太多时间和不喜欢破坏现有代码的混合物。
您可以通过几种方式解决此问题。您可以编写自己的字符串类,遵循对this
的右值引用。您可以从std::string
下降并专门阻止operator=
。您可以编写一个具有std::string
的访问者对象,该对象可以隐式地转换为std::string&&
广告std::string&
(基于this
的rvalue状态),但阻止赋值{ {1}}方法。
这三个都有问题。最后一个是最少的问题,第二个是最隐蔽的陷阱,第一个只是苦差事。