2010-12-13 19 views
2

基本クラスから数多くのクラス(50以上)を作成する必要があります。唯一の違いは派生クラスの名前にあります。私は現在、私はそれぞれが独自のコンストラクタを持つこの基本クラスから派生したクラスの多くを作成する必要がC++でのテンプレートプログラミングを使用して基本クラスから派生クラスを作成する方法は?

class BaseError : public std::exception 
{ 
private: 
    int osErrorCode; 
    const std::string errorMsg; 

public: 
    int ec; 
    BaseError() : std::exception(), errorMsg() {} 

    BaseError (int errorCode, int osErrCode, const std::string& msg) 
     : std::exception(), errorMsg(msg) 
    { 
     ec = errorCode; 
     osErrorCode = osErrCode; 
    } 

    BaseError (const BaseError& other) 
     : std::exception(other), errorMsg(other.errorMsg) 
    { 
     ec = other.errorCode; 
     osErrorCode = other.osErrorCode; 
    } 

    const std::string& errorMessage() const { return errorMsg; } 

    virtual ~BaseError() throw(){} 

} 

、コンストラクタおよび仮想デストラクタ関数をコピーします。たとえば

、私の基底クラスは次のように定義されますイムので、テンプレートを使用して作成し、これらのクラスを持っているいくつかの方法があります :

class FileError : public BaseError{ 
private: 
    const std::string error_msg; 

public: 
    FileError() :BaseError(), error_msg() {} 

    FileError (int errorCode, int osErrorCode, const std::string& errorMessage) 
     :BaseError(errorCode, osErrorCode, errorMessage){} 

    virtual ~FileError() throw(){} 
}; 

質問:午前のコピーが/必要に応じ名を変更したコードを貼り付けます補足は繰り返されませんか?

+1

少し関係のないコメント:代わりに、あなた自身の 'のconstのstd ::文字列&にErrorMessageを(提供する)const'仮想'のconstのchar *のstd ::例外::何を()const'機能を再実装する場合がありますゲッターあなたは 'std :: exception'を継承しています。 –

+2

なぜ派生クラスが必要ですか?単純な 'typedef'で十分ではないでしょうか?私が見た限りでは、派生クラスでは役に立ちません。 – Naveen

+0

派生クラスの動作が同じであれば、ホエーはテンプレート化されたクラスには行きませんか? – Arunmu

答えて

7

カスタムエラー処理を実装するために、catch句で動的ディスパッチを使用してコンパイラに頼って正しい型を見つけることができるように、クラス階層を作成するとします。これを行うには、BaseErrorクラスをそのままにしてから、複数のインスタンス化を提供するテンプレートクラスを追加します。このことを考えてみましょう:

class BaseError : public std::exception 
{ 
private: 
    int osErrorCode; 
    const std::string errorMsg; 

public: 
    int ec; 
    BaseError() : std::exception(), errorMsg() {} 

    BaseError (int errorCode, int osErrCode, const std::string& msg) 
     : std::exception(), errorMsg(msg) 
    { 
     ec = errorCode; 
     osErrorCode = osErrCode; 
    } 

    // ... 
}; 

template <int T> 
class ConcreteError : public BaseError { 
public: 
    ConcreteError() :BaseError(), error_msg() {} 

    ConcreteError (int errorCode, int osErrorCode, const std::string& errorMessage) 
     :BaseError(errorCode, osErrorCode, errorMessage){} 
}; 

あなたは今、いくつかのタイプの定義を設定することができます。

typedef ConcreteError<0> FileError; 
typedef ConcreteError<1> NetworkError; 
typedef ConcreteError<2> DatabaseError; 
// ... 

あなたは今、三つの異なるエラークラスと階層を持っています。

+0

私はこれをとても気に入っています(特に、後でこのスキームを壊さずに独自の実装を行うことをお勧めします)。追加するものだけが、整数値は定数または列挙の一部でなければなりません。 :) – Mephane

+0

これは、共有ライブラリからの例外のスローを許可しますか? –

+0

@Mephane:この場合、名前付き定数または列挙は何を与えますか?異なるクラスを持つだけで済みます。IDで名前を参照することはないので、IDの名前は必要ありません。 –

0

実装がまったく同じで、クラスごとに異なる名前が必要な場合は、単純なtypedefがあなたの仕事をします。

インターフェイスにはありませんが、実装に若干の違いがある場合は、おそらくテンプレートが必要です。次に、policy based designも考慮してください。

4

実装が同じ場合は、列挙型とテンプレートを作成します。

enum error { 
    file_error, 
}; 
template<error e> class my_exception : public BaseError { 
    .... 
}; 
typedef my_exception<file_error> file_exception; 
+0

+1列挙のために。 – Palmik

+0

この場合、名前付き定数または列挙型を使用するのはどうしてですか?異なるクラスを持つだけで済みます。IDで名前を参照することはないので、IDの名前は必要ありません。あなたは常にtypedefを使います。 –

+0

@Frerich:列挙によってそれらを参照できることは何も間違っていません。このソリューションには別の利点があります。 – Puppy

関連する問題