删除复制构造函数会破坏继承的构造函数

时间:2015-10-05 17:46:55

标签: c++ c++11 inheritance constructor copy-constructor

我正在尝试使用C ++ 11的构造函数继承功能。以下代码片段(从某处复制,我不记得从哪里开始)完全可以正常工作:

#include <iostream>

struct Base {
  Base() : Base(0) {}
  Base(int a) : Base(a, 0) {}
  Base(int a, double b) { std::cout << "Base(" << a << "," << b << ")" << std::endl; }
};

struct Derived : Base {
  using Base::Base;
  Derived(const Derived& that) = delete;  // This line is the culprit
};

int main(int argc, char* argv[]) {
  Derived d1;
  Derived d2(42);
  Derived d3(42, 3.14);
}

即,添加注释标记的行;因为那时所有的地狱都破裂了:

> g++ -std=c++11 -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18:11: error: no matching function for call to ‘Derived::Derived()’
   Derived d1;
           ^
test.cpp:18:11: note: candidates are:
test.cpp:13:16: note: Derived::Derived(int)
    using Base::Base;
                ^
test.cpp:13:16: note:   candidate expects 1 argument, 0 provided
test.cpp:13:16: note: Derived::Derived(int, double)
test.cpp:13:16: note:   candidate expects 2 arguments, 0 provided

似乎删除复制构造函数也会以某种方式使Base的默认构造函数不可访问。谷歌搜索问题没有带来任何有用的东西; SO建议this issue,但据我了解,我不在此代码段中使用复制初始化。有人可以对这里发生的事情有所了解吗?

(生成上述消息的编译器是GCC 4.8.2;但是,clang返回类似的错误消息。)

3 个答案:

答案 0 :(得分:11)

问题是使用delete标记复制构造函数会使其用户声明,这实际上会删除该类的默认构造函数(在您的情况下为Derived) 。这个行为可以在这个简单的代码中看到:

struct X
{
    X(const X&) = delete; // now the default constructor is not defined anymore
};

int main() 
{
    X x; // cannot construct X, default constructor is inaccessible 
}

作为旁注:即使继承Base::Base(),编译器也会看到它 Derived(): Base(){}。但Derived已删除,因此无法真正调用Base::Base()。通常,using Base::Base语句只是相应编译器生成的Derived(params): Base(params){}的语法糖。

答案 1 :(得分:4)

每当定义自定义构造函数时,都需要显式提供默认构造函数。即。

Derived::Derived() = default;

答案 2 :(得分:4)

继承构造函数并不能获得特殊的构造函数 - 空,复制,移动。这是因为你要求字面意思几乎总是一个坏主意。

检查:

struct base {
  std::vector<int> data;
  base(base const&)=default;
  base(base&&)=default;
  base(size_t n):data(n) {}
  base()=default;
};

struct derived:base {
  using base::base;
  std::vector<char> more_data;
};

真的希望derived(base const&)存在吗?还是base(base&&)?两者都无可救药地切片derived

这些操作发生的危险&#34;意外&#34;意味着你必须明确地将它们带入。

默认情况下,复制/移动/默认ctors恰好只调用父版本,加上成员变量的ctors。 (通常)不需要从父母那里继承它们。

但是,一旦你=delete=default或定义其中一个特殊ctors,其他的就停止由编译器生成。所以你必须=default其他的,如果你仍然希望他们坚持下去。