bjs*_*123 30 c++ operator-overloading assignment-operator
赋值运算符可以使用成员函数重载,但不能使用非成员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;
}
Run Code Online (Sandbox Code Playgroud)
它会导致此错误:
错误C2801:'operator ='必须是非静态成员
为什么friend
函数不能用于重载赋值运算符?编译器允许重载其他运算符,例如+=
和-=
使用friend
.支持的固有问题/限制是operator=
什么?
AnT*_*AnT 36
首先,应该注意的是,这与作为朋友具体实施的操作员无关.它实际上是将副本赋值实现为成员函数或非成员(独立)函数.这个独立功能是否会成为朋友是完全不相关的:它可能是,可能不是,取决于它想要在类中访问什么.
现在,这个问题的答案在D&E书(C++的设计和演变)中给出.原因是编译器总是为类声明/定义成员复制赋值运算符(如果您没有声明自己的成员复制赋值运算符).
如果该语言还允许将复制赋值运算符声明为独立(非成员)函数,则最终可能会出现以下情况:
// Class definition
class SomeClass {
// No copy-assignment operator declared here
// so the compiler declares its own implicitly
...
};
SomeClass a, b;
void foo() {
a = b;
// The code here will use the compiler-declared copy-assignment for `SomeClass`
// because it doesn't know anything about any other copy-assignment operators
}
// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);
void bar() {
a = b;
// The code here will use your standalone copy-assigment for `SomeClass`
// and not the compiler-declared one
}
Run Code Online (Sandbox Code Playgroud)
如上例所示,复制赋值的语义将在转换单元的中间发生变化 - 在声明独立运算符之前,将使用编译器的版本.声明后使用您的版本.程序的行为将根据您放置独立复制赋值运算符的声明的位置而改变.
这被认为是不可接受的危险(并且是),因此C++不允许将复制赋值运算符声明为独立函数.
确实,在您的特定示例中,恰好使用了友元函数,在类定义中很早就声明了运算符(因为这就是朋友的声明方式).因此,在您的情况下,编译器当然会立即知道您的运算符的存在.但是,从C++语言的角度来看,一般问题与朋友函数无关.从C++语言的角度来看,它是关于成员函数与非成员函数,并且由于上述原因,完全禁止非成员重载复制赋值.
Bil*_*eal 29
因为operator=
编译器提供的默认值(成员复制一个)总是优先.即你的朋友operator=
永远不会被召唤.
编辑:这个答案正在回答
什么是支持=运营商的固有问题/限制?
部分问题.这里的其他答案引用了标准部分,表示你不能这样做,但这很可能是为什么标准的那部分是这样编写的.
$ 13.5.3 - "赋值运算符应由具有一个参数的非静态成员函数实现.因为如果未由用户声明(12.8),则为类隐式声明了复制赋值运算符operator =,基类赋值运算符总是被派生类的副本赋值运算符隐藏."
因为有些运营商必须是会员.这些运营商是:
operator[]
operator=
operator()
operator->
和类型转换运算符一样operator int
.
虽然有人可能能够解释为什么operator =必须是成员,但他们的论证不能适用于列表中的其他人,这使我相信"为什么"的答案是"仅仅因为".
HTH