复制赋值运算符具有通常的签名:
my_class & operator = (my_class const & rhs);
下面的签名有什么实际用途吗?
my_class const & operator = (my_class const & rhs);
您只能定义一个或另一个,但不能同时定义两者。
复制赋值运算符具有通常的签名:
my_class & operator = (my_class const & rhs);
下面的签名有什么实际用途吗?
my_class const & operator = (my_class const & rhs);
您只能定义一个或另一个,但不能同时定义两者。
使复制赋值的返回类型成为非常量引用的主要原因是它是标准中对“可赋值”的要求。
如果您将返回类型设为const
引用,那么您的类将不符合在任何标准库容器中使用的要求。
不要那样做。它阻止客户端编写类似的内容:
(a = b).non_const_method();
而不是更长的形式:
a = b;
a.non_const_method();
虽然您可能不喜欢速记风格,但真正由库的用户决定他们想要如何编写代码。
一个反映C++ 中重载赋值运算符的答案:
返回 aconst&
仍然允许赋值链:
a = b = c;
但将不允许一些更不寻常的用途:
(a = b) = c;
请注意,这使得赋值运算符具有类似于它在 C 中的语义,其中=
运算符返回的值不是左值。在 C++ 中,标准对其进行了更改,因此=
运算符返回左操作数的类型,因此结果是左值。但是正如史蒂夫杰索普在对另一个答案的评论中指出的那样,虽然这使得编译器会接受
(a = b) = c;
即使对于内置插件,结果也是内置插件的未定义行为,因为a
它被修改了两次,没有中间的序列点。对于带有 an 的非内置函数,可以避免该问题,operator=()
因为operator=()
函数调用用作序列点。
我认为返回 a 没有问题,const&
除非您想特别允许左值语义(并设计类以确保它与这些语义明智地行动)。如果您的用户想要对 的结果做一些不寻常的事情operator=()
,我宁愿该类禁止它,而不是希望它偶然而不是设计正确。
还。请注意,当您说:
您只能定义一个或另一个,但不能同时定义两者。
这是因为 C++ 中的函数签名没有考虑返回值类型。但是,您可以有多个operator=()
赋值运算符,它们采用不同的参数并返回适合参数类型的不同类型:
my_class& operator=( my_class& rhs);
my_class const& operator=(my_class const& rhs);
我不完全确定这会给你带来什么。在这两种情况下,分配给的对象(可能是返回的引用)都是非常量的,因此没有逻辑理由仅仅因为isconst&
的右手边而返回 a 。但也许我错过了一些东西......=
const
Effective C++ 解释说,这会破坏与 C++ 内置类型的兼容性。
你可以用普通int
的 s 做到这一点:
(x = y) = z;
所以他的理由是,不管这看起来多么愚蠢,一个人也应该能够对自己的类型做同样的事情。
这个例子在第 2 版中有,虽然在第 3 版中没有了。然而,这句话来自第 3 版,第 10 条仍然说明了同样的情况:
[...] 赋值返回对其左侧参数的引用,这是为类实现赋值运算符时应遵循的约定:
class Widget {
public:
...
Widget& operator=(const Widget& rhs) // return type is a reference to
{ // the current class
...
return *this; // return the left-hand object
}
...
};
为什么大家都这么痴迷(a = b) = c
?这是偶然写的吗?
更改分配的结果可能有一些不可预见的效用。您不只是针对看起来很有趣的虚构示例制定任意规则。从语义上讲,它没有理由应该是const
,因此不要将其声明const
为词法副作用。
下面是一个有点合理的代码示例,它会因const &
分配而中断:
my_class &ref = a = b;
与 const 的任何其他用法一样,const 是默认值,除非您真的想让用户更改。
是的,应该是const
。否则客户可以这样做:
class MyClass
{
public:
MyClass & operator = (MyClass const & rhs);
}
void Foo() {
MyClass a, b, c;
(a = b) = c; //Yikes!
}