2015-10-05 18 views
8

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である。しかし、打ち鳴らすは、同様のエラーメッセージを返す)

+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

標準の用語は* user-declared *です。 –

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

「誤って」起こっている操作の危険性は、必要に応じて明示的に表示する必要があることを意味します。


copy/move/default ctorsは、デフォルトで親バージョンとメンバー変数のctorsを呼び出すだけです。あなたの親から継承する必要はありません(通常)。

ただし、=delete,=defaultのいずれかを定義するか、これらの特殊なctorsの1つを定義すると、もう1つはコンパイラによって生成されなくなります。あなたはまだそれらの周りに固執したい場合は=default他のものにする必要があります。

+0

説明をありがとう。 '= default'でもユーザが宣言したようにカウントされますか? –

+0

@DavidNemeskeyいいえ、まずは、私はうんざりでした。第二に、宣言されたユーザーは標準で定義されているフレーズ(私は信じている)であり、技術的な意味が慎重であるため、これらを使用することは避けています。しかし、 '= default'にはいくつかの効果があります。もしあなたが' 'デフォルト ''のコピー・コアー、ムーブ・コントーが抑止されていれば、その逆もあります。 [ライブサンプル](http://coliru.stacked-crooked.com/a/e1e31f3323dc0855)。これはnullary ctorの '= default'には当てはまりません。 [ライブサンプル](http://coliru.stacked-crooked.com/a/0c77e82287c0427e) – Yakk

関連する問題