2016-12-27 24 views
0

私の質問は、実際にはとても簡単です。そして、これは、ブーストのpythonで使用されているフレームリスナクラスとのpythonラッパークラスです:C++/Boost Pythonクラスのオーバーライド

class FrameListener 
    { 
    public: 

     struct FrameEvent 
     { 
      double TimeSinceLastEvent; 
      double TimeSinceLastFrame; 
     }; 

     FrameListener() {} 
     ~FrameListener() {} 

     virtual void FrameStart(FrameEvent& evt) = 0; 
     virtual void FrameEnd(FrameEvent& evt) = 0; 
     virtual void OnFrame(FrameEvent& evt) = 0; 
    }; 

    class FrameListener_PyWrapper : public FrameListener, public boost::python::wrapper<FrameListener> 
    { 
    public: 
     FrameListener_PyWrapper() {}  
     ~FrameListener_PyWrapper(); 

     void FrameStart(FrameEvent& evt); 
     void FrameEnd(FrameEvent& evt); 
     void OnFrame(FrameEvent& evt); 
    }; 

クラスは、その後のpythonを高めるためにラップされています

class_<SL_Engine::FrameListener::FrameEvent>("FrameEvent") 
     .def_readonly("TimeSinceLastEvent", &SL_Engine::FrameListener::FrameEvent::TimeSinceLastEvent) 
     .def_readonly("TimeSinceLastFrame", &SL_Engine::FrameListener::FrameEvent::TimeSinceLastFrame); 

    class_<SL_Engine::FrameListener_PyWrapper, boost::noncopyable>("FrameListener") 
     .def("OnFrame", pure_virtual(&SL_Engine::FrameListener::OnFrame)) 
     .def("FrameStart", pure_virtual(&SL_Engine::FrameListener::FrameStart)) 
     .def("FrameEnd", pure_virtual(&SL_Engine::FrameListener::FrameEnd)) 
     ; 

これは、独自のフレームを作成するためにpythonで上書きすることができリスナークラス:

class SimpleListen(FrameListener): 
def __init__(self): 
    pass 
def FrameEndd(self, evt): 
    pass 

その後、新しいSimpleListenerクラスのインスタンスを作成し、CORE_ENGINE.AddFrameListener()関数でエンジンにそれを「登録」。関数はboost :: python :: extract()を使ってそれを抽出し、それをフレームリスナーのstd :: vectorに入れ、フレームごとに実行します。これは完全に機能しますが、単純なクラスでベースを定義したりスペルミスを忘れるとクラッシュすることは明らかです。私はboost :: pythonまたはC/Python APIの両方でgoogleを検索しましたが、基底クラスが適切に定義されているかどうかをどのようにテストできますか? AddFrameListenerはPyObject *引数をとります。 PyObjectが最初にクラス型であるかどうかをテストしたいと思います。誤って整数値または文字列を入力しようとすると、プログラムはエラーを特定し、オブジェクトがクラス型ではないことを知らせます。もしそれがクラス型であれば、それは基本クラスを持っているかどうかをテストしたいし、FrameListener_PyWrapper *に抽出できるかどうかを調べたい。後で、私は個々の関数(FrameStart、FrameEnd、OnFrame)がPythonクラスでオーバーライドされ、引数が一致するかどうかをテストしたいと考えています。どのように私はPython関数から引数のリストを取得できますか? Pythonクラスの関数のどれかがオーバーライドされていなければ、それは私に警告を与えます。引数が一致せずに電話しようとすると:

if (boost::python::override f = this->get_override("FrameEnd")) 
    { 
     f(evt); 
     return; 
    } 

エラーについての情報なしでクラッシュする可能性があります。 AddFrameListener関数を呼び出すときに引数が一致するかどうかをチェックし、関数が適切にオーバーライドされない場合に情報を保存して、エンジンがそれらを呼び出さないようにしたい。

答えて

0

クラッシュは、GILをロックせずにPythonを呼び出しているという事実と関連している可能性があります。あなたは、Pythonのオブジェクトと対話するたび、あなたがそれをロックする必要があります。

/* 
This RAII structure ensures that threads created on the native C side 
adhere to the laws of Python and ensure they grab the GIL lock when 
calling into python 
*/ 
struct PyLockGIL 
{ 

    PyLockGIL() 
     : gstate(PyGILState_Ensure()) 
    { 
    } 

    ~PyLockGIL() 
    { 
     PyGILState_Release(gstate); 
    } 

    PyLockGIL(const PyLockGIL&) = delete; 
    PyLockGIL& operator=(const PyLockGIL&) = delete; 

    PyGILState_STATE gstate; 
}; 

次に、あなたは、Pythonにコールバックする前にそれを使用します。

if (override fe = this->get_override("FrameEnd")) 
{ 
    PyLockGIL lock; 
    try 
    { 
     fe(); 
     return; 
    } 
    catch (const error_already_set&) 
    { 
     std::cout << "Exception in FrameEnd in application"; 
     PyErr_Print(); 
    } 
} 
else 
{ 
    std::cout << "FrameEnd called but not overridden"; 
} 
関連する問題