[英]Extending a virtual C++ class exposed via Boost.Python
I am trying to expose this C++ class using Boost.Python: 我正在尝试使用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
}
My final goal is to define children of VAlgorithm in the python shell as python classes. 我的最终目标是在python shell中将VAlgorithm的子级定义为python类。 Following this example , I defined a callback class:
在此示例之后 ,我定义了一个回调类:
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;
};
Right now I am exposing only the class itself and the GetName() method. 现在,我只公开类本身和GetName()方法。 Since it is a virtual class, I placed this code inside BOOST_PYTHON_MODULE:
由于它是一个虚拟类,因此将这段代码放在BOOST_PYTHON_MODULE内:
class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", no_init) //
.def("GetName", &VAlgorithm_callback::GetName_default); //
I can compile this and load the module in the python shell. 我可以编译它并将模块加载到python shell中。 Then I try to define a child class and call the GetName() default implementation defined in the C++ code:
然后,我尝试定义一个子类,并调用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
I am not an expert (just facing these issues for the first time), but it seems to me that ConcAlg1 and ConcAlg3 try to instantiate a VAlgorithm object and fail because of the no_init parameter used when exposing VAlgorithm (I Can't omit it or the code won't compile), and ConcAlg2 can't call GetName() because somehow it is not recognized as a child of VAlgorithm. 我不是专家(只是第一次面对这些问题),但是在我看来,ConcAlg1和ConcAlg3试图实例化一个VAlgorithm对象并由于暴露VAlgorithm时使用了no_init参数而失败(我无法忽略它,或者代码将无法编译),并且ConcAlg2无法调用GetName(),因为某种程度上它不能被识别为VAlgorithm的子代。 I must be doing something trivially wrong but I can't figure out what (I am a novice of Boost.Python and extension).
我一定在做一些琐碎的错误,但是我不知道该怎么办(我是Boost.Python和扩展的新手)。 Can anyone please help me?
谁能帮帮我吗? Thanks
谢谢
I think I found the solution. 我想我找到了解决方案。 Going through the example I quoted on my ask, and also the boost documentation here , I figured that the problem is that the callback class is the real class being wrapped by Boost.Python, and that it has to be a concrete class.
通过我在提问中引用的示例以及此处的boost文档,我发现问题在于回调类是Boost.Python包装的真实类,它必须是一个具体的类。 So I implemented in it the missing pure virtual methods:
因此,我在其中实现了缺少的纯虚拟方法:
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;
};
and also modified the wrapper as: 并将包装器修改为:
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);
Now I can define a child class in Python and call the default GetName() method: 现在,我可以在Python中定义一个子类并调用默认的GetName()方法:
>>> class ConcAlg(VAlgorithm):
... pass
...
>>> c = ConcAlg("c")
>>> c.GetName()
'c'
>>>
I have done things quite similar to this. 我所做的事情与此非常相似。 Why don't you follow what you already have found in your comment ?
您为什么不遵循评论中已经找到的内容?
When you create an instance of a class deriving on VAlgorithm in Python, the VAlgorithm_callback will have to be instantiated in C++ to represent it. 当您在Python中创建派生于VAlgorithm的类的实例时,必须用C ++实例化VAlgorithm_callback来表示它。 It's not possible if you don't declare any constructor in BOOST_PYTHON_MODULE.
如果没有在BOOST_PYTHON_MODULE中声明任何构造函数,则是不可能的。
Doing the way its done in the example should be ok: 按照示例中的方式进行操作应该可以:
class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", init<std::string>())
When you define the init of the child class, you can use following syntax to call the parent constructor (but your code may work too, that's just the way I do). 定义子类的init时,可以使用以下语法调用父构造函数(但是您的代码也可以工作,这就是我的方法)。 In the example you used, they don't even define init so the parent one is called instead.
在您使用的示例中,它们甚至都没有定义init,因此调用了父级init 。
class ConcAlg3(VAlgorithm):
def __init__(self, name):
VAlgorithm.__init__(self, name)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.