我试图使用Boost.Python公开这个C ++类:
class VAlgorithm {
public:
VAlgorithm(const char *name);
virtual ~VAlgorithm();
virtual bool Initialize() = 0;
virtual bool Process() = 0;
virtual bool Finalize() = 0;
virtual const char *GetName() const; // Default implementation in cpp file
}
我的最终目标是将python shell中的VAlgorithm子项定义为python类。在this example之后,我定义了一个回调类:
class VAlgorithm_callback: public VAlgorithm {
public:
VAlgorithm_callback(PyObject *p, const char *name) :
self(p), VAlgorithm(name) {
}
const char * GetName() const {
return call_method<const char *>(self, "GetName");
}
static const char * GetName_default(const VAlgorithm& self_) {
return self_.VAlgorithm::GetName();
}
private:
PyObject *self;
};
现在我只暴露类本身和GetName()方法。由于它是一个虚拟类,我将此代码放在BOOST_PYTHON_MODULE:
中class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", no_init) //
.def("GetName", &VAlgorithm_callback::GetName_default); //
我可以编译它并在python shell中加载模块。然后我尝试定义子类并调用C ++代码中定义的GetName()默认实现:
>>> class ConcAlg1(VAlgorithm):
... pass
...
>>> c1 = ConcAlg1("c1")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: This class cannot be instantiated from Python
>>> class ConcAlg2(VAlgorithm):
... def __init__(self, name):
... pass
...
>>> c2 = ConcAlg2("c2")
>>> c2.GetName()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
VAlgorithm.GetName(ConcAlg2)
did not match C++ signature:
GetName(VAlgorithm)
>>> class ConcAlg3(VAlgorithm):
... def __init__(self, name):
... super(ConcAlg3, self).__init__(self, name)
...
>>> c3 = ConcAlg3("c3")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
RuntimeError: This class cannot be instantiated from Python
我不是专家(只是第一次面对这些问题),但在我看来,ConcAlg1和ConcAlg3尝试实例化VAlgorithm对象并因为暴露VAlgorithm时使用的no_init参数而失败(我不能省略它或代码将无法编译),并且ConcAlg2不能调用GetName(),因为不知何故它不被识别为VAlgorithm的子代。 我必须做一些简单的错误,但我无法弄清楚是什么(我是Boost.Python和扩展的新手)。谁能帮帮我吗?感谢
答案 0 :(得分:0)
我想我找到了解决方案。通过我的问题引用的示例,以及boost文档here,我认为问题在于回调类是由Boost.Python包装的真正类,并且它必须是具体的类。所以我在其中实现了缺少的纯虚方法:
class VAlgorithm_callback: public VAlgorithm {
public:
VAlgorithm_callback(PyObject *p, const char *name) :
self(p), VAlgorithm(name) {
}
virtual bool Initialize() {
return call_method<bool>(self, "Initialize");
}
virtual bool Process() {
return call_method<bool>(self, "Process");
}
virtual bool Finalize() {
return call_method<bool>(self, "Finalize");
}
const char * GetName() const {
return call_method<const char *>(self, "GetName");
}
// Supplies the default implementation of GetName
static const char * GetName_default(const VAlgorithm& self_) {
return self_.VAlgorithm::GetName();
}
private:
PyObject *self;
};
并将包装器修改为:
class_<VAlgorithm, boost::shared_ptr<VAlgorithm_callback>, boost::noncopyable ("VAlgorithm", init<const char *>()) //
.def("Initialize", &VAlgorithm_callback::Initialize)
.def("Process", &VAlgorithm_callback::Process)
.def("Finalize", &VAlgorithm_callback::Finalize)
.def("GetName", &VAlgorithm_callback::GetName_default);
现在我可以在Python中定义一个子类并调用默认的GetName()方法:
>>> class ConcAlg(VAlgorithm):
... pass
...
>>> c = ConcAlg("c")
>>> c.GetName()
'c'
>>>
答案 1 :(得分:0)
我做的事与此非常相似。为什么不按照你在评论中发现的内容进行操作?
当您在Python中创建在VAlgorithm上派生的类的实例时,必须在C ++中实例化VAlgorithm_callback来表示它。如果你不在BOOST_PYTHON_MODULE中声明任何构造函数,那是不可能的。
在示例中完成它的方式应该没问题:
class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", init<std::string>())
当您定义子类的 init 时,您可以使用以下语法来调用父构造函数(但您的代码也可以工作,这就是我的方式)。在您使用的示例中,它们甚至没有定义 init ,因此会调用父项。
class ConcAlg3(VAlgorithm):
def __init__(self, name):
VAlgorithm.__init__(self, name)