2016-10-02 9 views
1

私は開発中のC++アプリケーションの例外クラスの小さな階層を作成しており、間接的にはstd::runtime_errorから派生しています。ここで私はこれまでに書かれたものに類似したコードは次のとおりです。デフォルトのコンストラクタを持たない仮想ベースからクラスを派生させよう

class RuntimeException : public virtual boost::exception, public virtual std::runtime_error { 
public: 
    virtual ~RuntimeException() {} 
    RuntimeException() : runtime_error("A RuntimeException occurred.") {} 
    RuntimeException(const std::string& what) : runtime_error(what) {} 
}; 

class IllegalArgumentException : public virtual RuntimeException { 
public: 
    IllegalArgumentException() : RuntimeException("An IllegalArgumentException occurred.") {} 
    IllegalArgumentException(const std::string& what) : RuntimeException(what) {} 
}; 

RuntimeExceptionクラスは問題なくコンパイルが、エラー生成し、VS2015でコンパイルするIllegalArgumentExceptionを拒否:IllegalArgumentExceptionの両方のコンストラクタのためno default constructor exists for class "std::runtime_error"を。これは、私はこのコードがうまくコンパイルされると期待していたので、C++の継承階層の理解には挑戦しています。

私の理解では、それがstd::runtime_errorは、デフォルトコンストラクタを持っていないことは事実ですが、そのコンストラクタはRuntimeExceptionためにコンストラクタによって呼び出されている、のでIllegalArgumentExceptionコンパイルする必要があることです。しかし、コンパイラがそれを拒否しているので、明らかにこれはfalseでなければならない。 IllegalArgumentExceptionコンストラクタから直接std::runtime_errorコンストラクタを呼び出すことを望んでいるようですが(コンパイラエラーが消えてしまいます)、これはコンストラクタをの2回呼び出すので間違っています:RuntimeExceptionのコンストラクタで、 IllegalArgumentExceptionのコンストラクタで再度呼び出します。

これは安全かつ効率的ですか?そうでない場合、なぜコンパイラはそれを推奨しているようですか?私はstd::exceptionから派生し、std::string自分自身をメンバ変数として実装していますが、すでにこれを実装している標準クラスから派生する方が簡単だと思いました。これは間違ったアプローチですか?さらに、私がこの問題に寄与するboost:exceptionstd::runtime_errorの両方から事実上派生しているという事実はありますか?

答えて

2

virtualvirtual継承ベースのコンストラクタコールを使用して最も派生クラスの責任ではなく、任意の中間クラスの責任です。理由は明らかです:virtualの継承を使用すると、基本クラスを使用して実際に複数の派生クラスが存在することが予想されます。これらの派生クラスのどれがvirtualベースの構築に責任を持つでしょうか?

ので、派生クラスのいずれかのコンストラクタがvirtual塩基、例えばに引数を提供する必要がある:中間の塩基がvirtual継承することを目的virtual基底クラスのコンストラクタを呼び出すことを避けるために

IllegalArgumentException::IllegalArgumentException(std::string const& what) 
    : std::runtime_error(what) 
    , RuntimeException(what) { 
} 

多くの場合、デフォルトのコンストラクタを提供します。もちろん、これは、最も派生したクラスが、その基底の1つによって呼び出された適切なコンストラクタに間違って依存している可能性を示します。

+0

ありがとう、あなたの説明は非常に明確です。これを踏まえて、私は 'std :: exception'から派生し、自分自身の' std :: string'を使って終わる可能性が最も高いです。それは行くのが一番簡単な方法です。 –

関連する問題