2010-12-13 6 views
2

Ich muss eine Anzahl von Klassen (mehr als 50) aus einer Basisklasse erstellen, wobei der einzige Unterschied in den Namen der abgeleiteten Klassen besteht.Wie erstellt man abgeleitete Klassen aus einer Basisklasse mit Template-Programmierung in C++?

Zum Beispiel ist meine Basisklasse definiert als:

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(){} 

} 

ich viel abgeleiteten Klassen von dieser Basisklasse zu schaffen, haben jeweils ihre eigene Konstrukteure haben, Copy-Konstruktor und die virtuelle Destruktorfunktion, ich derzeit am Kopieren/Einfügen der Code die Namen zu ändern, wenn nötig:

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(){} 
}; 

Frage: gibt es eine Möglichkeit, diese Klassen haben Vorlagen verwendet, so dass die im Plementation wird nicht wiederholt?

+1

Etwas nicht verwandten Kommentar: Statt der eigenen 'const std :: string & Bereitstellung errormessage() const' Sie den virtuellen' const char * std :: exception reimplementieren Getter möchten :: was() const' Funktion Sie bekommen durch Übernahme von 'std :: exception'. –

+2

Warum benötigen Sie abgeleitete Klassen? Wird ein einfacher 'typedef' nicht ausreichen? Soweit ich sehe, gibt es in abgeleiteten Klassen nichts Brauchbares. – Naveen

+0

Wenn das Verhalten Ihrer abgeleiteten Klassen gleich bleibt, dann sollten Sie sich nicht für die templated Klasse entscheiden? – Arunmu

Antwort

7

Ich nehme an, Sie möchten eine Klassenhierarchie erstellen, so dass Sie dynamischen Versand in Ihren catch-Klauseln verwenden können (basierend auf dem Compiler, um den richtigen Typ herauszufinden), um benutzerdefinierte Fehlerbehandlung zu implementieren. Sie können dies tun, indem Sie die BaseError-Klasse beibehalten und eine Vorlagenklasse hinzufügen, für die Sie dann mehrere Instanziierungen bereitstellen. Bedenken Sie:

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){} 
}; 

können Sie nun eingerichtet einige Typdefinitionen:

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

Sie jetzt eine Hierarchie mit drei verschiedenen Fehlerklassen haben.

+0

Ich mag das, sehr elegant (besonders, dass Sie später immer spezifische Ausnahmen ihre eigene Implementierung geben, ohne dieses Schema zu brechen). Die einzige Sache, die hinzugefügt werden muss, ist, dass die Integer-Werte entweder Konstanten oder Teil einer Enumeration sein sollen. :) – Mephane

+0

Ermöglicht dies das Auslösen von Ausnahmen von einer gemeinsam genutzten Bibliothek? –

+0

@Mephane: Was würden Sie benannte Konstanten oder eine Aufzählung in diesem Fall geben? Sie müssen nur verschiedene Klassen haben - Sie werden sich nie auf die ID beziehen, also brauchen Sie keine Namen für die IDs. –

0

Wenn die Implementierung genau gleich ist und Sie nur einen anderen Namen für jede Klasse haben möchten, dann würde simple typedef Ihre Aufgabe erfüllen.

Und wenn es einen kleinen Unterschied in der Implementierung gibt, aber nicht in der Schnittstelle, dann brauchen Sie wahrscheinlich Vorlagen. Dann bedenken Sie auch policy based design.

4

Wenn die Implementierungen identisch sind, erstellen Sie eine Enumeration und eine Vorlage.

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

+1 Für die Aufzählung. – Palmik

+0

Warum sollten Sie in diesem Fall benannte Konstanten oder eine Aufzählung verwenden? Sie müssen nur verschiedene Klassen haben - Sie werden sich nie auf die ID beziehen, also brauchen Sie keine Namen für die IDs. Sie verwenden immer nur die typedefs. –

+0

@Frelich: Nichts falsch daran, auf sie durch Aufzählung verweisen zu können. Es ist ein zusätzlicher Vorteil für diese Lösung. – Puppy

Verwandte Themen