当我只想禁用它时,自定义赋值运算符=()的签名是否重要?

时间:2016-05-29 08:16:13

标签: c++ operator-overloading assignment-operator

我需要禁用复制赋值运算符。这将有效:

A& operator=(const A&);

如果我没有为operator=指定确切的参数,它会起作用吗? 我的意思是这样的:

void operator=(void);

返回值是对的,我可以写任何我想要的,但参数类型怎么样?
这会覆盖类的默认operator=吗?

3 个答案:

答案 0 :(得分:13)

来自C ++标准草案的12.8p17

  

用户声明的复制赋值运算符X::operator=是类X的非静态非模板成员函数,其中只有一个类型XX&的参数, const X&volatile X&const volatile X&

我想这比任何其他测试或示例代码都要好。

请注意,类似的内容也适用于移动赋值运算符,请参阅12.8p19

  

用户声明的移动赋值运算符X :: operator =是类X的非静态非模板成员函数,其中只有一个类型为X&&&&&&&&&&&&&& ,或const volatile X&&。

这些也证实,正如您所猜测的那样,返回值类型并不重要。

答案 1 :(得分:8)

可以有不同类型的作业。编译器可能只生成复制分配移动分配。如果没有复制/移动分配,则生成它们。因此,如果要禁用复制和/或移动赋值,则参数类型确实很重要,尽管存在一些灵活性,因为复制赋值可以使用不同的参数类型。但是,返回类型并不重要。

class A {
public:
    void operator=() = delete; // not legal: assignment takes exactly one argument
    void operator=(A) = delete; // OK: copy assignment disabled
    void operator=(A&) = delete; // OK: copy assignment disabled
    void operator=(A const&) = delete; // OK: copy assignment disabled
    void operator=(A&&) = delete; // OK: move assignment disabled
};

还有const替换volatileconst volatile符合复制/移动分配的变体。禁用复制分配时,也将禁用自动生成移动分配。如果禁用移动分配,我认为仍会生成复制分配。如果禁用任何不能复制或移动分配的内容,仍会生成复制/移动分配。

答案 2 :(得分:5)

这是来自current standard的用户声明的副本赋值运算符的精确定义(第12.8页,第17页):

  

用户声明的复制赋值运算符X::operator=是非静态的   class X的非模板成员函数,其中只有一个参数   输入X, X&, const X&, volatile X&const volatile X&

注意:

  • 必须将重载的赋值运算符声明为只有一个 参数;见13.5.3。
  • 可以为类声明多种形式的复制赋值运算符。
  • 如果类X只有一个带有X&类型参数的复制赋值运算符,则不能将类型为const X的表达式赋给类型为X的对象。

示例:

struct X {
X();
X& operator=(X&);
};
const X cx;
X x;
void f() {
x = cx; // error: X::operator=(X&) cannot assign cx into x
}

另外,请使用C ++ 11标准中的删除

您现在可以将功能设置为默认或已删除。

您现在可以直接写入要禁用复制的内容。

class A {
A(const A&) = delete;
A& operator=(const A&) = delete;    // Disallow copying
};

您还可以显式通知编译器您需要类的默认副本。这样,您可以提供自定义默认构造函数,并仍然可以从编译器获取其他编译器生成的方法的默认版本。

class B {
    B(const Y&) = default;
    B& operator=(const B&) = default;   // default copy 
};