2016-12-22 7 views
1

プログラムコンポーネントの例外クラスの階層を設計する際に問題が発生しました。 このコンポーネントには、いくつかの障害ケース(たとえば、std::bad_allocstd::invalid_argument、など)があり、非常に具体的な障害ケースごとに、上記の一般的な例外カテゴリから派生した対応する例外クラスを作成しました。例外クラスの多重継承

ここでは、すべての例外クラスを単一のクラス(例:Base)から派生させるように要求されました。クライアントは、失敗が自分のコンポーネントかどうかを知るために、Baseをキャッチします。しかし、私のコンポーネントの別のクライアントが、例外が発生した場所には関心がありませんが、なぜそれが発生したのかについては興味がありません。したがって、私の例外クラスは、一般的な標準例外クラスだけでなく、単一の区別された基本クラスBaseの両方から派生しなければならないようです。

私の質問は:Basestd::exceptionから派生させるべきですか?

std :: exceptionから派生している場合は、標準例外クラスが仮想継承を使用していないように見えるため、各例外クラス内に2つのstd :: exceptionインスタンスが存在する必要があります。私はこのケースでは例外クラスごとに変換演算子をstd::exceptionに書く必要があり、それは非常に退屈なようです。

std :: exceptionから派生していない場合、Baseを捕捉したいクライアントは、基本クラス内に実装しない限り、std :: exceptionの能力を使用できません。たとえばwhat()です。そうであれば、すべての例外クラスは本質的に1つの能力のために2つの名前を持ちますが、それはばかげているようです。また、クライアントがstd::exceptionから派生した例外クラスを期待している他の人にそれを戻すことを望む場合、クライアントは何らかの形で再パックする必要がありますが、これは非常に望ましくありません。

どうすればよいですか?

編集: 2番目のクライアントの要求は、彼/彼女が使用している非常に多くのコンポーネントがあるので、彼/彼女は同時に、あまりにも投げて、むしろ私が作ったものよりも、標準の例外クラスを使用したいということです多くの種類の例外があるので、すべての失敗事例を認識できません。

答えて

0

std::exceptionから派生する必要はありません。あなたがそうするならば、事実上継承する。少し遅くなりますが、避けられないtry-catchの隣に目立つことはありません。

はまた、あなたが書いたものをもとに、あなたは、単にマルチレベルの継承を持つことができる、ということに注意してください:

class Base : public std::exception { ... }; 
class BadAlloc : public Base { ... }; 
class InvalidArg : public Base { ... }; 

編集:

あなたは別の階層のメンバーから階層を継承したいので、テンプレートパラメータとして2番目のパラメータが必要です。あなたは、ベース/ BaseImplパラダイムとそれにカスタムベースクラスを注入することができます

class Base 
{ 
public: 
    virtual int getTheMeaning() const = 0; 
}; 

template<typename SecondBase = std::exception> 
class BaseImpl : public Base, public SecondBase 
{ 
public: 
    BaseImpl(int localMeaning) : meaning_(localMeaning * 3) {} 
    int getTheMeaning() const override { return meaning_; } 

private: 
    const int meaning_; 
}; 

class InvalidArg : public BaseImpl<std::logic_error> 
{ 
public: 
    InvalidArg() : BaseImpl<std::logic_error>(14) {} 
}; 

その後、あなたは私が何をしたいと考えているである、const std::logic_error&またはconst Base&のいずれかをキャッチすることができます。これは、const Base&が依然としてBaseImpl<>に実装された仮想関数を持つことができ、したがって明示的な詳細が後者によって駆動されるという利点があります。

+0

はい私は 'std :: exception'から派生することができますが、私が質問したように、' std :: exception'の2つのインスタンスがあるので、 'std :: exception'への変換はあいまいになります。仮想継承は役に立たない。 'std :: logic_error'はそれを使用しません。 –

+0

いいえ - あなたが仮想的に継承している場合、唯一のものがあります。これは、敢えてダイヤモンドの問題に対する解決策と呼ばれています。 – lorro

+0

それはすべての基本クラスが実質的にグランドベースクラスを継承する場合にのみ起こりますね。私の場合、 'Base'は仮想継承を使用できますが、' std :: logic_error'はそれを使用しません。 –