首先需要注意的是,这与具体实现为友元的算子无关。它实际上是将复制分配实现为成员函数或非成员(独立)函数。该独立函数是否会成为朋友完全无关紧要:它可能是,也可能不是,取决于它想在类中访问什么。
现在,这个问题的答案在 D&E 书(The Design and Evolution of 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
}
如上例所示,复制赋值的语义会在翻译单元的中间发生变化——在声明独立运算符之前,使用编译器的版本。声明后使用您的版本。程序的行为将根据您将独立复制赋值运算符的声明放在哪里而改变。
这被认为是不可接受的危险(确实如此),因此 C++ 不允许将复制赋值运算符声明为独立函数。
确实,在您的特定示例中,恰好专门使用了朋友函数,运算符在类定义中很早就声明了(因为这是声明朋友的方式)。因此,在您的情况下,编译器当然会立即知道您的运算符的存在。但是,从 C++ 语言的角度来看,一般问题与友元函数没有任何关系。从 C++ 语言的角度来看,它是关于成员函数与非成员函数的,由于上述原因,完全禁止复制赋值的非成员重载。