2014-10-31 133 views
1

这可能是一个微不足道的问题,但我没有找到满意的答案,不能真正弄清楚发生了什么。超载运营商=

假设你有下面的代码:

#include <iostream> 

class Foo 
{ 
public: 
    void operator=(int) 
    { 
     std::cout << "calling Foo::operator=(int)" << std::endl; 
    } 
}; 

int main() 
{ 
    Foo a, b; 
    a = 10; // it works, of course, no questions here 
    a = b; // why does this work? 
} 

由于我在Foo超载operator=,我希望行a = bmain()吐编译器错误(即a.operator=(b)不应该编译,因为有没有从bint的隐式转换,后者是输入类型Foo::operator=(int))。为什么分配a = b默默地工作,究竟发生了什么?编译器是否会产生一个“默认”operator=(const Foo&),即使在我重载它的情况下?

回答

1

是的,编译器正在生成一个默认的,平凡的Foo& operator=(const Foo&)。目前只有四种情况的隐含拷贝赋值运算符就不会发生:

  • 你明确告诉它不要(如Foo& operator=(const Foo&) = delete
  • 你宣布一个自己服用Foo(或Foo&const Foo&
  • 类具有非平凡转让的成员(如unique_ptr<T>
  • 你的类有一个定义的移动赋值运算符或构造函数(感谢布赖恩)

更新以下是标准中的一些相关部分。

18年8月12日:

如果类定义不明确声明拷贝赋值运算符,一个是隐式声明。如果 类定义声明移动构造函数或移动赋值运算符,则将隐式声明的副本 赋值运算符定义为已删除;否则,它被定义为默认

好吧,不过你没声明一个拷贝赋值运算符,对不对?还是你?究竟一个拷贝赋值运算符:

17年8月12日:

用户声明的拷贝赋值运算符X::operator=X 类恰好与一个参数的非静态的非模板成员函数类型XX&,const X&,volatile X&const volatile X&。 121 [注意: 重载赋值运算符必须声明为只有一个参数;见13.5.3。 - 结束注释] [注意:可以为一个类声明多种形式的复制赋值运算符。 - 注完] [注: 如果一个类X只与X&类型的参数的拷贝赋值运算符,const X 类型的表达式不能分配给类型X

的对象,因此没有。您作为赋值运算符声明为Foo::operator=(int)的函数不是复制赋值运算符。因此它不符合前一段中不隐式声明的条件。

所有其它条件在23年8月12日所定义:

类X A拖欠复制/移动赋值运算符被定义为已删除如果X具有:

  • 变体构件使用非平凡的相应赋值运算符,并且X是类联合类,或者是非常量非类类型(或其数组)的非静态数据成员,或者是
  • 参考类型的非静态数据成员,或
  • 类型为M(或其数组)的非静态数据成员,因为应用于M的相应分配,因此无法复制/移动,因为 重载决议(13.3)运算符会导致模糊 或从默认赋值运算符中删除或不可访问的函数,或导致直接或虚拟基类B由于过载解析(13.3)而无法复制/移动,因为 应用于B相应的赋值运算符,会导致模糊或被删除的功能 或缺省赋值运算符无法访问,或者
  • 为移动赋值运算符,非静态数据成员或类型为 没有移动赋值运算符并且不是可以简单复制的类型的直接基类或任何直接或间接虚拟 基类。
+0

谢谢,看来你知道标准:)你有一秒钟。数? – vsoftco 2014-10-31 02:05:25

+0

如果存在显式声明的移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符也将被定义为删除。 – Brian 2014-10-31 02:05:31

+0

@布莱恩,谢谢,我知道,对于赋值运算符只是好奇心。似乎有点奇怪,不能为重载操作符指定“显式”。这可能很有用,特别是在处理代理对象时。 – vsoftco 2014-10-31 02:08:51