为什么不允许使用友元函数重载“=”? 我写了一个小程序,但它给出了错误。
class comp
{
int real;
int imaginary;
public:
comp(){real=0; imaginary=0;}
void show(){cout << "Real="<<real<<" Imaginary="<<imaginary<<endl;}
void set(int i,int j){real=i;imaginary=j;}
friend comp operator=(comp &op1,const comp &op2);
};
comp operator=(comp &op1,const comp &op2)
{
op1.imaginary=op2.imaginary;
op1.real=op2.real;
return op1;
}
int main()
{
comp a,b;
a.set(10,20);
b=a;
b.show();
return 0;
}
编译给出以下错误: -
[root@dogmatix stackoverflow]# g++ prog4.cpp
prog4.cpp:11: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp:14: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp: In function ‘int main()’:
prog4.cpp:25: error: ambiguous overload for ‘operator=’ in ‘b = a’
prog4.cpp:4: note: candidates are: comp& comp::operator=(const comp&)
prog4.cpp:14: note: comp operator=(comp&, const comp&)
答案 0 :(得分:17)
因为如果你没有将它声明为一个类成员,编译器会为你编写一个,它会引起歧义。
答案 1 :(得分:9)
明确要求赋值运算符是类成员运算符。这是编译器无法编译代码的充分理由。赋值是标准中定义的特殊成员函数之一(如复制构造函数),如果您不提供自己的函数,将由编译器生成。
与可以理解为左侧操作符外部的其他操作不同,赋值是一个语义绑定到左侧的操作:将此实例修改为等于到右侧实例(通过等于的某些定义),因此将它作为类的操作而不是外部操作是有意义的。另一方面,作为添加的其他运算符不绑定到特定实例:a+b
是a
或b
的操作还是没有? - a
和b
用于操作,但操作操作
实际上建议并使用该方法:将operator+=
(适用于实例)定义为成员函数,然后将operator+
实现为对结果<进行操作的自由函数/ EM>:
struct example {
example& operator+=( const example& rhs );
};
example operator+( const example& lhs, const example& rhs ) {
example ret( lhs );
ret += rhs;
return ret;
}
// usually implemented as:
// example operator+( example lhs, const example& rhs ) {
// return lhs += rhs; // note that lhs is actually a copy, not the real lhs
//}
答案 2 :(得分:1)
Assignment(=)运算符是一个特殊的运算符,当程序员没有提供(重载)作为类的成员时,构造函数将提供给类。(如复制构造函数)。
当程序员使用友元函数重载=运算符时,将存在两个=操作:
1)编译器提供=运算符
2)程序员通过朋友功能提供(重载)=运算符
然后,将简单地创建歧义,编译器将给出错误。它的编译错误。
答案 3 :(得分:0)
没有充分的理由,我认为Stepanov提议应该有一个免费的operator=
,并且可以用它来做很多好事(甚至比移动分配所能做的更多)。我找不到引用,但Stepanov甚至建议构造函数可以是自由函数http://www.stlport.org/resources/StepanovUSA.html。
有一种解决方法,就是在所有类中系统地声明一个template<class Other> A& operator=(Other const& t);
,这样您就可以将选项留给任何人来定义自定义赋值运算符。
当然,对于您无法控制的类,您不能这样做。
已经说过,由于我们已经进行了移动分配,因此现在 还不错。从某种意义上说,转换运算符B::operator A() const{...}
几乎就像一个自定义副本分配。由于explicit
,现在可以使用转换运算符。但是,您必须控制第二种类型(B
),即分配中的右侧类型。
下一个问题是,为什么转换运算符需要自己成为成员?同样,我认为没有充分的理由。