2015-10-05 155 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