从基类调用最终类构造函数

Invoke final class constructor from base class

本文关键字:构造函数 基类 调用      更新时间:2023-10-16

我有一个异常类,如下所示:

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 的最终类调用构造函数呢?

你试图做的事情违背了多个 SOLID 原则。你也使你的基类与它的后代紧密耦合(!)。你绝对不希望这样。它应该不知道谁继承了。

要做到这一点,请覆盖子类中的 Wrap 函数,它们基本上在其中抛出自己。在你的代码中,你将使用StandardError.Wrap(...

但老实说,我只会将异常留在代码中。

(无论条件如何 ->抛出异常)在代码中都很好,并且比使用静态方法的另一个异常中的异常更具可读性。

当您

不应该再重构它时,就是这种情况。