1

我想正常重载一个常见的复制赋值运算符。一开始我使用了一个只需要对源进行 const 引用的接口,并显式禁用了接受可修改引用的接口,但我无法通过编译。编译器报告“错误:使用已删除的函数 'ClassA& ClassA::operator=(ClassA&)”

当然,如果我不明确删除接口,我可以编译,但这不是我的目的。我想明确删除它,以避免意外使用它。

为什么复制赋值操作需要对源的可修改引用,而不是 const 引用?赋值操作只需要以只读方式访问源!

关于复制构造函数也有同样的问题,为了简化我省略了它。

我的代码有什么问题?或者我们不能删除它?

我的示例代码如下:

class ClassA {
public:
   ClassA() = default;
   ClassA( ClassA & ) = default;

   ClassA & operator=( ClassA & )
   = delete   // Must comment-out this, or we can't pass the compilation.
   // { cout << "ClassA & operator=( ClassA & ) executed." << endl; return *this; }
   ;

   ClassA & operator=( ClassA && ) {
      cout << "ClassA & operator=( ClassA && ) executed." << endl;
      return *this;
   };

   ClassA & operator=( const ClassA & ) {
      cout << "ClassA & operator=( const ClassA & ) executed." << endl;
      return *this;
   };
   ClassA & operator=( const ClassA && ) {
      cout << "ClassA & operator=( const ClassA && ) executed." << endl;
      return *this;
   };
};

int main() {
   ClassA oa, ob;
   ob = oa;

   return EXIT_SUCCESS;
};
4

3 回答 3

4

或者我们不能删除它?

你只是不需要这样做。如果您提供用户定义的复制赋值运算符,则不会隐式声明其他运算符,即仅存在用户定义的运算符。

如果这样做,您明确标记为的复制赋值运算符delete将参与重载决议;当它被选中时,编译失败。对于ob = oa;operator=( ClassA & )是更好的匹配,如果不存在,operator=( const ClassA & )将被使用并正常工作。

所以在这种情况下你可以做

class ClassA {
public:

   ClassA & operator=( ClassA && ) {
      cout << "ClassA & operator=( ClassA && ) executed." << endl;
      return *this;
   }

   ClassA & operator=( const ClassA & ) {
      cout << "ClassA & operator=( const ClassA & ) executed." << endl;
      return *this;
   }
};
于 2019-05-28T09:11:25.680 回答
2

当然,如果我不明确删除接口,我可以编译,但这不是我的目的。我想明确删除它,以避免意外使用它。

你不能意外地使用不存在的东西。如果您的类定义了ClassA & operator=( const ClassA & ),则ClassA & operator=( ClassA & )根本不存在(编译器不会生成它)。没有理由提供和删除它。

于 2019-05-28T09:11:51.173 回答
1

如果您明确删除它,并且您调用:

ob = oa;
// The same as
ob.operator=(oa);

当然ClassA & operator=( ClassA & )是最好的匹配,因为oa它是非常量左值。既然被删除了,就会报错。

如果根本没有声明,则ClassA & operator=( const ClassA & )现在成为最佳匹配。所以它永远不会尝试使用ClassA & operator=( ClassA & ),因为它不存在。

如果您真的想要,您仍然可以拥有ClassA & operator=( ClassA & ) = delete;,并且您必须手动从 const 引用中分配:

ob = static_cast<const ClassA&>(oa);
// Will now select `ClassA & operator=( const ClassA & )`

这表明您不需要非常量左值赋值运算符。ClassA & operator=( ClassA & )但实际上没有意义,因为如果未声明,它将被用作 const 引用。

于 2019-05-28T09:15:16.213 回答