这是一个小例子,可以满足我的要求。整个过程的中心是使用一个“holder”类,它告诉 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)
;
}
但有一些警告:
如果您没有go
在继承自 的 Python 中实现Base
,您将收到一条关于无限递归的无用 Python 异常消息。如果有默认实现,我也不确定如何使虚函数回退到 C++(您可能可以通过查看 的代码来弄清楚bp::wrapper
,它做了非常相似的事情)。
如果您Base
通过引用或指针从 C++ 函数返回一个对象,您将不会有一个包含PyBase
对象的 Python 对象,除非您返回的实例实际上是一个 PyBase 对象(如果您考虑一下,这是有道理的)课程)。
如果要按值返回,则需要添加一个以 a 作为其第一个参数的复制构造函数,然后才能从调用PyObject*
中删除boost::noncopyable
模板参数。bp::class_
构造函数中的Py_INCREF
语句告诉 Python “您的代码”正在对该对象进行额外引用。但是我不清楚你想如何添加相应的Py_DECREF
: 如果你只有 a对象,那么std::map
以后Base*
就没有办法从中得到 aPyObject*
了。
解决上述问题的一种方法是拥有一个bp::handle<>
or的容器bp::object
,并构造其中一个 fromself
放入容器中。但在这种情况下,您需要确保在程序结束之前清空这些容器,因为如果在静态析构函数时调用 Python 析构函数,您将遇到分段错误。