2015-10-05 156 views
8

我想使用C++ 11的构造函数继承特性。下面的代码段(从某处复制,我不记得从那里)的作品完全没问题:删除复制构造函数break继承构造函数

#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;然而,铛返回类似的错误消息)

+1

默认的构造函数没有被继承。 –

+0

T.C.怎么会这样?在Derived d1;行中,我清楚地看到调用了Base()。 –

+0

@ T.C。词的选择是误导性的。当然,构造函数是继承的 - 否则,你将无法从派生类中调用它们。它只用于不同的课程。 – SergeyA

回答

10

的问题是标记一个拷贝构造与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){}的语法糖。

+0

那是我错过的链接。从来没有想过删除一些东西可以算作“定制”它。谢谢! –

+0

@DavidNemeskey是的,这确实很混乱,但它就是这样工作的。 – vsoftco

+0

标准术语是*用户声明*。 –

4

无论何时定义自定义构造函数,都需要明确提供默认构造函数。即

Derived::Derived() = default; 
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

这些操作发生“意外”的危险意味着您必须明确地将它们带入,如果您想要它们。


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

但是,一旦你=delete=default或定义其中一个特殊ctors,其他一些停止生成的编译器。所以你必须要=default其他的,如果你还想让他们坚持下去的话。

+0

感谢您的解释。即使'=默认'计为用户声明? –

+0

@DavidNemeskey号码首先,因为我很sl。。其次,因为用户声明是标准中定义的一个短语(我相信),并且我避免使用这些短语,因为它们具有谨慎的技术含义。但'= default'可以产生一些效果 - 如果''default'复制文件,移动文件被压缩,反之亦然。 [现场示例](http://coliru.stacked-crooked.com/a/e1e31f3323dc0855)。 '= default'同样不适用于nullary ctor。 [现场示例](http://coliru.stacked-crooked.com/a/0c77e82287c0427e) – Yakk