Вызвать конструктор финального класса из базового класса

У меня есть класс исключения следующим образом:

class ExtensionExceptionType;
class Object;

class Exception
{
public:
explicit Exception () { }

Exception(                      const std::string &reason ) { PyErr_SetString( _Exc_RuntimeError(), reason.c_str() ); }
Exception( PyObject* exception, const std::string &reason ) { PyErr_SetString( exception,           reason.c_str() ); }

Exception( PyObject* exception, Object& reason );

Exception( ExtensionExceptionType& exception, const std::string& reason );
Exception( ExtensionExceptionType& exception, Object&            reason );

void clear() { PyErr_Clear(); } // clear the error -- technically but not philosophically const

static Object err_type();
static Object err_value();
static Object err_trace();

static Object err_stats( uint32_t i ); // 0 1 2 for {type, value, trace}

static void wrap( int condition ) {
if( condition == -1 )
throw Exception{};
}
};

// Abstract
class StandardError     : public Exception      { protected: explicit StandardError()    {} };

class LookupError       : public StandardError  { protected: explicit LookupError()      {} };
class ArithmeticError   : public StandardError  { protected: explicit ArithmeticError()  {} };
class EnvironmentError  : public StandardError  { protected: explicit EnvironmentError() {} };

// Concrete (π)

// e.g.
//    class TypeError: public StandardError
//    {
//    public:
//        TypeError (const std::string& reason)
//        : StandardError()
//        {
//            PyErr_SetString( Py::_Exc_TypeError(),reason.c_str() );
//        }
//    };

#define CONCRETE( CLASS, BASE ) \
class CLASS: public BASE \
{ \
public: \
CLASS (const std::string& reason) \
{ \
std::cout << "(Exception.hxx) " #CLASS " from PyCXX (" << reason.c_str() << ") \n"; \
PyErr_SetString( _Exc_##CLASS(), reason.c_str() ); \
} \
};

// it appears that these classes are only for manually RAISING Python errors
// i.e. Raising an exception in the Python runtime
// because if I type something in to the Python console, I can make (e.g.) a KeyError occur, but these classes don't get hit.

CONCRETE( TypeError,            StandardError   )
CONCRETE( IndexError,           LookupError     )
CONCRETE( AttributeError,       StandardError   )
CONCRETE( NameError,            StandardError   )
CONCRETE( RuntimeError,         StandardError   )
CONCRETE( NotImplementedError,  StandardError   )
CONCRETE( SystemError,          StandardError   )
CONCRETE( KeyError,             LookupError     )
CONCRETE( ValueError,           StandardError   )
CONCRETE( OverflowError,        ArithmeticError )
CONCRETE( ZeroDivisionError,    ArithmeticError )
CONCRETE( FloatingPointError,   ArithmeticError )
CONCRETE( MemoryError,          StandardError   )
CONCRETE( SystemExit,           StandardError   )

Я только что добавил:

    static void wrap( int condition ) {
if( condition == -1 )
throw Exception{};
}

… потому что было много случаев в других местах …

if( SomePythonFunc(...) == -1 ) throw Exception{};

… которые были убраны в:

Exception.wrap( SomePythonFunc(...) ); // much nicer, I think

Тем не менее, есть также случаи:

if( SomePythonFunc(...) == -1 ) throw TypeError{ "foo" };

… и я не вижу, как выполнить эквивалентную упаковку.

т.е. написать:

TypeError.wrap( SomePythonFunc(...), "foo" );

Поскольку TypeError: Exception и Exception :: wrap общедоступны, я могу просто создать необязательный второй параметр для wrap:

    static void wrap( int condition, string err="default-err" ) {
if( condition == -1 )
throw FinalClassConstructor{ err }; // <-- how to do this?
}

… но как мне тогда вызвать конструктор для последнего класса, чей :: wrap только что получил?

0

Решение

То, что вы пытаетесь сделать, противоречит нескольким принципам SOLID. Вы также делаете свой базовый класс тесно связанным (!) С его потомками. Вы определенно не хотите этого. Он не должен знать, кто наследует.

Чтобы сделать это правильно, переопределите функцию Wrap в дочерних классах, куда они себя бросают. В вашем коде вы пойдете StandardError.Wrap (…

Но если честно, я бы просто оставил исключения в коде.

(WHATEVER CONDITION -> Throw исключение) прекрасно работает в коде и является более читабельным, чем исключение в другом исключении со статическим методом.

Это тот случай, когда вы больше не должны его рефакторировать.

2

Другие решения


По вопросам рекламы [email protected]