我试图在python中创建一个类,它覆盖C类中的(纯)虚函数(使用boost.python
)。问题是C类是通过静态成员函数创建的(所有的构造函数都是私有的或被删除的)。我已经成功地创建了Base类和一个Python“知道”的BaseWrap类。我也已经能够创建一个可以在python中重写的纯虚函数。然而,我的问题是当Base的成员函数调用纯虚函数时。当这种情况发生时,类无法找到python实现,程序崩溃。
下面是C++代码:
#include <iostream>
#include <boost/python.hpp>
#include <boost/static_assert.hpp>
#define CREATE(NAME) \
static std::shared_ptr<NAME> Create() { \
std::cout << "STATIC BASE CREATE" << std::endl; \
return std::make_shared<NAME>(); \
}
class Base {
protected:
Base() { std::cout << "BASE DEFAULT CONSTRUCTOR" << std::endl; }
private:
std::string CallSay() {
return Say();
}
virtual std::string Say() const = 0;
};
class BaseWrap : public Base, public boost::python::wrapper<Base> {
public:
BaseWrap() : Base() { std::cout << "BASEWRAP DEFAULT CONSTRUCTOR" << std::endl; }
virtual std::string Say() const override
{
std::cout << "C++ Say" << std::endl;
return this->get_override("say") ();
}
CREATE(BaseWrap)
};
BOOST_PYTHON_MODULE(Example)
{
namespace python = boost::python;
// Expose Base.
python::class_<BaseWrap, std::shared_ptr<BaseWrap>, boost::noncopyable>("Base", python::no_init)
.def("__init__", python::make_constructor(&BaseWrap::Create))
.def("Say", python::pure_virtual(&Base::Say))
.def("CallSay", &Base::CallSay);
}
Python代码来测试这个问题:
import sys
import Example
class PythonDerived(Example.Base):
def __init__(self):
print "PYTHON DEFAULT CONSTRUCTOR"
Example.Base.__init__(self)
def Say(self):
return "Python Say"
d = PythonDerived()
print d
print
print d.Say()
print
print d.CallSay()
运行时,给出输出:
PYTHON DEFAULT CONSTRUCTOR
STATIC BASE CREATE
BASE DEFAULT CONSTRUCTOR
BASEWRAP DEFAULT CONSTRUCTOR
<__main__.PythonDerived object at 0x1091caf70>
Python Say
C++ Say
Traceback (most recent call last):
File "test.py", line 20, in <module>
print d.CallSay()
TypeError: 'NoneType' object is not callable
看起来Base::CallSay
方法正在查找BaseWrap::Say
的实现,但无法找到python实现。有人知道为什么或如何使其工作吗?
谢谢!
3条答案
按热度按时间mo49yndu1#
这看起来好像是Boost.Python中的一个bug。
boost::python::wrapper
层次结构没有在从boost::python::make_constructor
返回的函子中初始化。由于wrapper
层次结构没有Python对象的句柄,get_override()
返回NoneType
,并且尝试调用NoneType
会引发TypeError
异常。要解决这个问题,可以显式地初始化
wrapper
层次结构。下面是一个完整的示例,提供了一种通用的方法来实现这一点。可以使用make_wrapper_constructor()
而不是使用make_constructor()
。我选择不使用C11特性。因此,将有一些样板代码可以使用可变模板来减少,但移植到C11应该是相当简单的。它的用法:
jdgnovmf2#
我找到了一个工作,似乎解决了这个问题。这是一个有点“黑客”的感觉,所以如果任何人有一个更好的解决方案,将不胜感激。
基本上我写了一个helper类,所以C++代码变成了:
Python代码:
它的工作...但不是作为一个优雅的修复,因为我希望。
hiz5n14c3#
我意识到这是一个几乎十年前的问题,但如果有人正在通过使用自定义策略寻找一个优雅的解决方案,我将在这里讨论这个问题。