Frage

Ich möchte oft neue ‚Exception‘ Klassen definieren, sondern müssen einen geeigneten Konstruktor definiert haben, weil Konstruktoren werden nicht vererbt.

class MyException : public Exception 
{ 
public:
  MyException (const UString Msg) : Exception(Msg)
  {
  };
}

Typedefs nicht für diese Arbeit, weil sie einfach Aliase sind, keine neuen Klassen. Derzeit zu vermeiden diese trivialen vorformulierten wiederholen, verwende ich eine #define, die die donkeywork tut.

#define TEXCEPTION(T) class T : public Exception \
{ \
public:\
    T(const UString Msg) : Exception(Msg) {}; \
}

...

TEXCEPTION(MyException);

Aber ich frage mich halten, wenn es ein besserer Weg, dies zu erreichen - vielleicht mit Vorlagen oder eine neue C ++ 0x-Funktion

War es hilfreich?

Lösung

Wenn Sie wirklich neue Klassen von Exception abgeleitet haben wollen, im Gegensatz zu einer Vorlage durch einen Parameter parametriert hat, gibt es keinen Weg, um Ihren eigenen Konstruktor schreiben, dass die Delegierten nur die Argumente, ohne einen Makro. C ++ 0x wird die Fähigkeit haben, was Sie brauchen, um so etwas wie

mit
class MyException : public Exception 
{ 
public:
    using Exception::Exception;
};

Sie können über die Details, dass lesen (scheinen ziemlich viel zusätzlichen Regeln zu haben) in 12,9 „Vererben Constructors“ in der neuester Entwurf von C ++ 0x .

In der Zwischenzeit würde ich eine Politik basiertes Design empfehlen (kleinen Text, weil der OP die oben angenommen, und diese Politik nicht Sachen):

// deriving from Impl first is crucial, so it's built first
// before Exception and its Ctor can be used.
template<typename Impl>
struct ExceptionT : Impl, Exception {
    // taking a tuple with the arguments.
    ExceptionT(arg_types const& t = arg_types())
        :Exception(Impl::Ctor(t)) { }
    // taking a string. plain old stuff
    ExceptionT(std::string const& s):Exception(Impl::Ctor(s)) { }
};

struct ExceptionDefImpl {
    typedef boost::tuple<> arg_types;

    // user defined ctor args can be done using a tuple
    std::string Ctor(arg_types const& s) {
        return std::string();
    }

    std::string const& Ctor(std::string const& s) {
        return s;
    }
};

// will inherit Ctor modifier from DefImpl.
struct MemoryLost : ExceptionDefImpl { 
    typedef boost::tuple<int> arg_types;

    std::string Ctor(arg_types const& s) {
        std::ostringstream os;
        os << "Only " << get<0>(s) << " bytes left!";
        return os.str();
    }

    int getLeftBytes() const { return leftBytes; }
private:
    int leftBytes;
};

struct StackOverflow : ExceptionDefImpl { };

// alias for the common exceptions
typedef ExceptionT<MemoryLost> MemoryLostError;
typedef ExceptionT<StackOverflow> StackOverflowError;

void throws_mem() {
    throw MemoryLostError(boost::make_tuple(5));
}    

void throws_stack() { throw StackOverflowError(); }

int main() {
    try { throws_mem(); } 
    catch(MemoryListError &m) { std::cout << "Left: " << m.getLeftBytes(); }
    catch(StackOverflowError &m) { std::cout << "Stackoverflow happened"; }
}

Andere Tipps

Sie können Ihre Template-Klasse mit einer ganzen Zahl parametrieren:

#include <iostream>
#include <string>

using namespace std;

enum ExceptionId {
    EXCEPTION_FOO,
    EXCEPTION_BAR
};

class Exception {
    string msg_;

public:
    Exception(const string& msg) : msg_(msg) { }
    void print() { cout << msg_ << endl; }
};

template <int T>
class TException : public Exception {
public:
    TException(const string& msg) : Exception(msg) {};
};

void
foo()
{
    throw TException<EXCEPTION_FOO>("foo");
}

void
bar()
{
    throw TException<EXCEPTION_BAR>("bar");
}

int
main(int argc, char *argv[])
{
    try {
        foo();
    } catch (TException<EXCEPTION_FOO>& e) {
        e.print();
    };

    try {
        bar();
    } catch (TException<EXCEPTION_BAR>& e) {
        e.print();
    };

    return 0;
}

Obwohl, ich sehe nicht, warum diese über mit einer einzigen Klasse mit einer internen Zählung begünstigen würde, das gesetzt wird / zur Laufzeit gelesen:

class TException {
public:
    enum Type { FOO, BAR };

    TException(Type type, const string& msg) : Exception(msg), type_(type) {}

    Type type() const { return type_; }

private:
    Type type_;
};

Dann schalten Sie einfach auf den Typ, wenn Sie einen TException fangen ...

// You could put this in a different scope so it doesn't clutter your namespaces.
template<struct S>   // Make S different for different exceptions.
class NewException :
    public Exception 
{ 
    public:
        NewException(const UString Msg) :
            Exception(Msg)
        {
        }
};

// Create some new exceptions
struct MyExceptionStruct;    typedef NewException<MyExceptionStruct> MyException;
struct YourExceptionStruct;  typedef NewException<YourExceptionStruct> YourException;
struct OurExceptionStruct;   typedef NewException<OurExceptionStruct> OurException;

// Or use a helper macro (which kinda defeats the purpose =])
#define MAKE_EXCEPTION(name) struct name##Struct; typedef NewException<name##Struct> name;

MAKE_EXCEPTION(MyException);
MAKE_EXCEPTION(YourException);
MAKE_EXCEPTION(OurException);

// Now use 'em
throw new MyException(":(");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top