为什么我们不能使用友元函数重载“=”?

时间:2010-05-19 11:30:49

标签: c++

为什么不允许使用友元函数重载“=”? 我写了一个小程序,但它给出了错误。

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&)

4 个答案:

答案 0 :(得分:17)

因为如果你没有将它声明为一个类成员,编译器会为你编写一个,它会引起歧义。

答案 1 :(得分:9)

明确要求赋值运算符是类成员运算符。这是编译器无法编译代码的充分理由。赋值是标准中定义的特殊成员函数之一(如复制构造函数),如果您不提供自己的函数,将由编译器生成。

与可以理解为左侧操作符外部的其他操作不同,赋值是一个语义绑定到左侧的操作:将此实例修改为等于到右侧实例(通过等于的某些定义),因此将它作为类的操作而不是外部操作是有意义的。另一方面,作为添加的其他运算符不绑定到特定实例:a+bab的操作还是没有? - ab用于操作,但操作操作

返回的结果

实际上建议并使用该方法:将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),即分配中的右侧类型。

下一个问题是,为什么转换运算符需要自己成为成员?同样,我认为没有充分的理由。