2015-06-17 60 views
1

我有一個Python類,它是從C++類派生的,並覆蓋了部分函​​數。 C++函數接收Python類的對象並將其存儲在向量中,因此GC類不應收集Python類。我嘗試了兩種不同的方法,但第一個不能編譯,第二個不會在運行時看到重寫(C++的函數被調用而不是Python類的函數)。請告訴我什麼是正確的做法。Boost Python:無法調用Python派生類中覆蓋的C++虛函數

的C++代碼:

class MyClass 
{ 
public: 
    virtual void PureVirtual(int i) = 0; 
    virtual const char* VirtualWithDefaultImpl() 
    { 
     return "MyClass"; 
    } 
}; 

void MyFnc(boost::shared_ptr<MyClass> obj) 
{ 
    myVector.push_back(obj); 
    std::cout << obj->VirtualWithDefaultImpl() << std::endl; 
    obj->PureVirtual(0); 
} 

python封裝:

class MyClassWrap : public MyClass, wrapper<MyClass> 
{ 
public: 
    MyClassWrap(PyObject* self) : m_self(self) 
    { 
     Py_INCREF(self); 
    } 
    MyClassWrap(PyObject* self, const MyClass& other) : MyClass(other), m_self(self) 
    { 
     Py_INCREF(self); 
    } 
    ~MyClassWrap() 
    { 
     Py_DECREF(m_self); 
    } 
    virtual void PureVirtual(int i) 
    { 
     this->get_override("PureVirtual")(i); 
    } 
    virtual const char* VirtualWithDefaultImpl() 
    { 
     if (override f = this->get_override("VirtualWithDefaultImpl")) 
      return f(); 
     return MyClass::VirtualWithDefaultImpl(); 
    } 
    const char* DefaultVirtualWithDefaultImpl() 
    { 
     return this->MyClass::VirtualWithDefaultImpl(); 
    } 
private: 
    PyObject* m_self; 
}; 

BOOST_PYTHON_MODULE(MyModule) 
{ 
    // First approach: 
    // Fails in compilation with error C2243: 'type cast' : conversion from 
    // 'MyClassWrap *' to 'boost::python::wrapper<T> *' exists, but is inaccessible 
    //class_<MyClassWrap, boost::shared_ptr<MyClassWrap>, boost::noncopyable>("MyClass") 

    // Second approach: 
    // Doesn't see the overrides at runtime 
    class_<MyClass, boost::shared_ptr<MyClassWrap>, boost::noncopyable>("MyClass") 
     .def("PureVirtual", pure_virtual(&MyClass::PureVirtual), args("i")) 
     .def("VirtualWithDefaultImpl", &MyClass::VirtualWithDefaultImpl, 
      &MyClassWrap::DefaultVirtualWithDefaultImpl); 
    def("MyFnc", &MyFnc, args("obj")); 
} 

的Python代碼:

class PythonDerived(MyModule.MyClass): 
    def PureVirtual(self, i): 
     print i 

    def VirtualWithDefaultImpl(self): 
     return 'PythonDerived' 

MyModule.MyFnc(PythonDerived()) 

第二助跑的輸出。正如你所看到的MyClass函數調用,而不是PythonDerived功能:

MyClass 

File "z:\tmp\tmp.py", line 11, in <module> 
    MyModule.MyFnc(PythonDerived()) 

TypeError: 'NoneType' object is not callable 

回答

0

我已經修改了你的包裝類,它是如何接觸到蟒蛇,現在正在按預期工作:

class MyClassWrap : public MyClass, public python::wrapper<MyClass> 
{ 
public: 
    MyClassWrap() : MyClass() 
    { 
    } 

    virtual void PureVirtual(int i) 
    { 
     this->get_override("PureVirtual")(i); 
    } 
    virtual const char* VirtualWithDefaultImpl() 
    { 
     if (python::override f = this->get_override("VirtualWithDefaultImpl")) 
      return f(); 
     return MyClass::VirtualWithDefaultImpl(); 
    } 
    const char* DefaultVirtualWithDefaultImpl() 
    { 
     return this->MyClass::VirtualWithDefaultImpl(); 
    } 

}; 

BOOST_PYTHON_MODULE(MyModule) 
{ 
python::class_<MyClassWrap, boost::shared_ptr<MyClassWrap>, boost::noncopyable>("MyClass") 
    .def("PureVirtual", python::pure_virtual(&MyClassWrap::PureVirtual), python::args("i")) 
    .def("VirtualWithDefaultImpl", &MyClassWrap::VirtualWithDefaultImpl, 
     &MyClassWrap::DefaultVirtualWithDefaultImpl); 
    python::def("MyFnc", &MyFnc, python::args("obj")); 
} 

輸出:

PythonDerived 
0 
+0

非常感謝您的快速響應!我認爲你的修復可能是一個問題。 MyFnc接收到的共享指針不會阻止GC收集PythonDerived對象(請參見[link](https://wiki.python.org/moin/boost.python/HowTo)一節)「在Python中擴展的C++對象的所有權「)。正如我在我的原始問題中提到的,PythonDerived對象由MyFnc存儲在一個向量中供將來使用,因此必須防止GC對PythonDerived對象的收集。 – user3240228