c++ - 默认赋值构造函数 - 运算符重载函数




为什么不能使用非成员函数来重载赋值运算符? (6)

为什么友元函数不能用于重载赋值运算符?

简短的回答: 只是因为

更长的答案:这就是语法修复的方式。 一些运营商必须是会员职能 。 赋值运算符是其中之一,

赋值运算符可以使用成员函数重载,但不能使用非成员friend函数重载:

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

它会导致此错误:

错误C2801:'operator ='必须是非静态成员

为什么不能使用friend函数来重载赋值运算符? 编译器允许使用friend重载其他运算符,例如+=-= 。 支持operator=的固有问题/限制是什么?


$ 13.5.3 - “赋值运算符应由具有一个参数的非静态成员函数实现。 因为如果未由用户声明(12.8),则为类隐式声明复制赋值运算符operator =,基类赋值运算符总是被派生类的副本赋值运算符隐藏。“


operator=的意图是对当前对象的赋值操作。 然后LHS或左值是相同类型的对象。

考虑LHS是整数或其他类型的情况。 这是由operator int()或相应的operator T()函数处理的情况。 因此,已经定义了LHS的类型,但是非成员operator=函数可能违反了这一点。

因此可以避免。


这篇文章适用于C ++ 11

为什么有人想要一个非会员operator= ? 好吧,使用成员operator=然后可以使用以下代码:

Test const &ref = ( Test() = something ); 

这创造了一个悬垂的参考。 非会员运营商会解决这个问题:

Test& operator=(Test &obj1, Test obj2)

因为现在prvalue Test()将无法绑定到obj1 。 事实上,这个签名会强制我们永远不会返回一个悬空引用(当然,除非我们提供了一个) - 该函数总是返回一个“有效”左值,因为它强制使用左值调用。

但是在C ++ 11中,现在有一种方法可以指定只能在左值上调用成员函数,因此可以通过编写成员函数来实现相同的目标:

Test &operator=(Test obj2) &
//                        ^^^

现在上面带有悬空引用的代码将无法编译。

NB。 operator=应该通过值或const引用来获取右侧。 在实现复制和交换习惯用法时 ,按值取值很有用,这是一种轻松编写安全(但不一定是最快)的复制赋值和移动赋值运算符的技术。


因为有些运营商必须是会员。 这些运营商是:
operator[]
operator=
operator()
operator->

和类型转换运算符,如operator int

虽然有人可能能够解释为什么operator =必须是成员,但他们的论点不能适用于列表中的其他人,这使我相信“​​为什么”的答案是“仅仅因为”。

HTH


因为编译器提供的默认operator= (成员复制一个)总是优先。 即你的朋友operator=永远不会被召唤。

编辑:这个答案正在回答

什么是支持=运营商的固有问题/限制?

部分问题。 这里的其他答案引用标准的部分,表示你不能这样做,但这很可能是为什么标准的那部分是这样编写的。







assignment-operator