隐式删除子项时继承父级赋值运算符

rcv*_*rcv 3 c++ inheritance move using-declaration c++11

在GCC 4.6中,即使由于移动构造函数而隐式删除子节点的赋值运算符,也可以继承父节点的赋值运算符.在GCC的后续版本(以及Clang)中,这已不再可能.让子类使用父类赋值运算符的正确方法是什么?

struct A
{
  A & operator=(A const & other) = default;
};

struct B : public A
{
  B() {}
  B(B && other) {}

  using A::operator=;
};

int main()
{
  B b1, b2;
  b1 = b2; // error: use of deleted function because B's operator= is implicitly deleted due to move constructor
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*eas 6

仍会声明已删除的函数,仅删除该定义.在类定义中扩展它:

struct B : A {
   using A::operator=;               // A& operator=(const A&)
   B& operator=(const B&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

此时,您可以注意到operator=派生类型中有两个声明,第一个声明(通过using声明引入范围)接受一个const A&参数,而第二个声明取一个const B&删除.

当您稍后尝试分配时:

B b1, b2;
b1 = b2;
Run Code Online (Sandbox Code Playgroud)

编译器都可以看到这两个声明,第二个是更好的匹配.因为它被标记为已删除,您将收到错误消息.另一方面,如果你有一个A对象,它将按预期工作:

B b1, b2;
b1 = static_cast<A&>(b2); // works, BUT...
Run Code Online (Sandbox Code Playgroud)

这种方法的问题在于它只复制了可能不是你想要的基础子对象.如果您只想要与编译器生成赋值所需的相同行为,则需要请求它:

struct B : A {
   // ...
   B& operator=(const B&) = default;
};
Run Code Online (Sandbox Code Playgroud)