这里不是const修饰符吗?
“ 有效的C ++ ”第3项说“尽可能使用常量”,它给出了一个例子:
const Rational operator*(const Rational& lhs, const Rational& rhs);
防止客户犯下这样的暴行:
Rational a, b, c; ... (a * b) = c; // invoke operator= on the result of a*b!
但不是函数的非参考返回值已经是右值 ? 那么为什么要这样做呢?
重点是对于类types (但不适用于内置types), a = b
只是a.operator=(b)
的缩写,其中operator =是成员函数。 成员函数可以在由Rational::operator*
创build的rvalues (a * b)
上调用。 为了执行类似于内置rvalues的语义(“ do as the int do ”),一些作者(Meyers包括)在C ++ 98中推荐用const rvalue来返回与这样的操作符类。
但是,在C ++ 11中,通过const-rvalue返回是一个坏主意,因为它会禁止移动语义,因为const rvalues不能绑定到T&&
。
在他的笔记对新的C ++(C ++ 11)的概述中 ,Scott Meyers给出了与他的旧书完全相同的例子,并得出结论:现在认为增加const返回值的devise很糟糕。 现在推荐的签名
Rational operator*(const Rational& lhs, const Rational& rhs);
更新:正如@ JohannesSchaub-litb在注释中所暗示的那样,在C ++ 11中,你也可以在赋值运算符上使用一个引用限定符 ,以便它只接受左值作为其左参数(即*this
指针,这就是为什么这个特性也被称为“* this的右值引用”)。 你需要g ++> = 4.8.1(刚刚发布)或者Clang> = 2.9才能使用它。
返回值上的const修饰符不是必需的,可以阻碍移动语义。 防止在C ++ 11中赋值为rvalues的首选方法是使用“ ref-qualifiers” 。
struct Rational { Rational & operator=( Rational other ) &; // can only be called on lvalues }; Rational operator*( Rational const & lhs, Rational const & rhs ); Rational a, b, c; (a * b) = c; // error
也许这会花费我的代表点,但我不同意。 不要修改重载操作符的预期返回types,因为它会惹恼你的类的用户。 即使用
Rational operator*(const Rational& lhs, const Rational& rhs);
(当然,build立参数是一个很好的做法,并且具有不变的引用参数会更好,因为这意味着编译器不会获得深层的副本,但是在这种情况下没有一个常量引用返回值,一个悬而未决的参考是灾难性的,但是请注意,有时候,引用比传递更慢,我认为double
s和int
s在许多平台上都属于这个类别。
因为你可能打算写(a * b) == c
而不是ie
if ((a * b) = (c + d)) // executes if c+d is true
但你想
if ((a * b) == (c + d)) // executes if they're equal
我想根据你的问题你想做什么是宣布相应的运营商=私人,使它不能访问了。
因此你想重载符合(a*b) = c
的签名。 我同意,左边的部分是一个expression式,因此右值是更好的匹配。 然而,如果你重载函数返回一个右值,那么你忽略了这个函数的返回值,编译器会抱怨无效的重载,因为重载规则不考虑返回值。
如上所述,赋值运算符的重载始终是一个内部类的定义。 如果会有一个非成员签名像void operator=(foo assignee, const foo& assigner);
重载决议可以匹配的第一部分作为一个右值(那么你可以删除它或宣布它是私人的)。
所以你可以select两个世界:
- 生活在这样的事实,用户可以写(愚蠢的东西,如
(a*b) = c
这是没有错,但存储在一个不可访问的临时 - 使用不符合
(a*b) = c
的签名const foo operator*(const foo& lhs, const foo& rhs)
并牺牲移动语义
码
#include <utility> class foo { public: foo() = default; foo(const foo& f) = default; foo operator*(const foo& rhs) const { foo tmp; return std::move(tmp); } foo operator=(const foo& op) const { return op; } private: // doesn't compile because overloading doesn't consider return values. // conflicts with foo operator=(const foo& op) const; foo && operator=(const foo& op) const; }; int main ( int argc, char **argv ) { foo t2,t1; foo t3 = t2*t1; foo t4; (t2 * t1) = t4; return 0; }