這是一個小例子,它可以做我想要的東西。整個過程圍繞着使用一個「持有者」類,它告訴Boost.Python在Python中構造特定類型的實例時實際使用不同的類,並且它應該將Python對象作爲第一個參數傳遞給自定義的任何構造函數包裝類。您可以在這裏找到更多的信息:
http://www.boost.org/doc/libs/1_48_0/libs/python/doc/v2/class.html
(見特別是 「HeldType語義」 的討論)。
#include "boost/python.hpp"
namespace bp = boost::python;
class Base {
public:
virtual double go(int x) const = 0;
virtual ~Base() {}
};
class PyBase : public Base {
public:
explicit PyBase(PyObject* self) : _self(self) {
Py_INCREF(_self); // THIS LEAKS MEMORY IF THERE'S NO DECREF!
}
virtual double go(int x) const {
return bp::call_method<double>(_self, "go", x);
}
private:
PyObject * _self;
};
BOOST_PYTHON_MODULE(example) {
bp::class_<Base,PyBase,boost::noncopyable>(
"Base",
bp::init<>() // the PyObject* arg is implicit
)
.def("go", &PyBase::go)
;
}
但也有一些注意事項:
如果不從Base
繼承了Python實現go
,你會得到關於無限遞歸無益的Python異常信息。我也不確定如果有一個默認的實現(如果你想通過查看代碼bp::wrapper
,它可以做出非常相似的事情)來讓虛擬函數回落到C++。
如果從C++函數通過引用或指針返回Base
對象,你會不會有一個包含PyBase
對象,除非你居然回來是PyBase對象開始與實例的Python對象(這是有道理的如果你考慮它,當然)。
如果要通過價值回報,你需要添加一個拷貝構造函數,一個PyObject*
作爲第一個參數,然後才能從bp::class_
呼叫刪除boost::noncopyable
模板參數。
構造函數中的Py_INCREF
語句告訴Python「您的代碼」正在對此對象進行額外的引用。但是我不清楚你想如何添加相應的Py_DECREF
:如果你只有一個std::map
的Base*
對象,那麼以後就無法獲得PyObject*
。
解決上述問題的一種方法是將容器bp::handle<>
或bp::object
,並將self
中的其中一個放入容器中。但是在那種情況下,你需要確保在程序結束之前清空這些容器,因爲如果在靜態析構函數時調用了一個Python析構函數,就會出現分段錯誤。
誰放置在容器中的對象? – Dani
忽略它的C++構造函數已被Python調用。 –
我意識到我說的是模棱兩可的。我談論的容器只包含引用,而不包含對象本身。它實際上是指針的std :: map。 –