示例代码说明:
struct Base { virtual int foo() = 0; }; struct Derived : public Base { virtual int foo() { return 42; } }; Base* get_base() { return new Derived; } BOOST_PYTHON_MODULE(libTestMod) { py::class_<Base>("Base",py::no_init) .def("foo",py::pure_virtual(&Base::foo)); py::def("get_base",get_base,py::return_internal_reference<>()); //ignore mem leak }
> Base :: foo不会在python中被覆盖
> Base:foo将在c中实现,但不应该暴露在python中
试过上面的代码,但无法编译.
更新:
编译错误:
/path/to/boostlib/boost/1.53.0-0/common/include/boost/python/object/value_holder.hpp:66:11: error: cannot declare field 'boost_1_53_0::python::objects::value_holder<Base>::m_held' to be of abstract type 'Base' Main.C:59:8: note: because the following virtual functions are pure within 'Base': Main.C:61:15: note: virtual int Base::foo()
解决方法
抽象C类不能以这种方式暴露给Boost.Python. Boost.Python
tutorial提供了如何公开纯虚拟函数的示例.简而言之,当使用boost :: python :: pure_virtual装饰方法时,需要创建一个包装类型,以允许C多态解析虚拟函数,虚拟函数实现将委托Python对象的层次结构中的多项解析函数.
struct BaseWrap : Base,boost::python::wrapper<Base> { int foo() { return this->get_override("foo")(); } }; ... boost::python::class_<BaseWrap>("Base",...) .def("foo",boost::python::pure_virtual(&Base::foo)) ;
有关详细信息,当通过boost :: python :: class_公开类型时,HeldType默认为要暴露的类型,并且HeldType在Python对象中构建. class_
文档规定:
Template Parameter:
T
: The class being wrappedHeldType
: Specifies the type that is actually embedded in a Python object wrapping aT
instance […]. Defaults toT
.
因此,boost :: python :: class_< Base>将失败,因为T = Base和HeldType = Base,Boost.Python将尝试将HeldType的对象实例化为表示Base实例的Python对象.这个实例化将失败,因为Base是一个抽象类.
这是一个完整的示例,显示了使用BaseWrap类.
#include <boost/python.hpp> struct Base { virtual int foo() = 0; virtual ~Base() {} }; struct Derived : public Base { virtual int foo() { return 42; } }; Base* get_base() { return new Derived; } namespace python = boost::python; /// @brief Wrapper that will provide a non-abstract type for Base. struct BaseWrap : Base,python::wrapper<Base> { BaseWrap() {} BaseWrap(const Base& rhs) : Base(rhs) {} int foo() { return this->get_override("foo")(); } }; BOOST_PYTHON_MODULE(example) { python::class_<BaseWrap>("Base") .def("foo",python::pure_virtual(&Base::foo)); ; python::def("get_base",&get_base,python::return_value_policy<python::manage_new_object>()); }
及其用途:
>>> import example >>> class Spam(example.Base): ... pass ... >>> Spam().foo() Traceback (most recent call last): File "<stdin>",line 1,in <module> RuntimeError: Pure virtual function called >>> class Egg(example.Base): ... def foo(self): ... return 100 ... >>> e = Egg() >>> e.foo() 100 >>> d = example.get_base() >>> d.foo() 42
在Boost.Python中暴露一个抽象类是可能的,它没有默认的初始化器(boost :: python :: no_init)和不可复制(boost :: noncopyable).缺少一个初始化器可以防止Python类型从中有效地避免重写.另外,Base :: foo()在C中由Derived实现的实现细节是无关紧要的.如果Python根本不知道一个foo()方法,那么通过def()来忽略它.
#include <boost/python.hpp> struct Base { virtual int foo() = 0; virtual ~Base() {} }; struct Derived : public Base { virtual int foo() { return 42; } }; struct OtherDerived : public Base { virtual int foo() { return 24; } }; Base* get_base() { return new Derived; } Base* get_other_base() { return new OtherDerived; } BOOST_PYTHON_MODULE(example) { namespace python = boost::python; python::class_<Base,boost::noncopyable>("Base",python::no_init) ; python::class_<Derived,python::bases<Base> >("Derived",python::no_init) .def("foo",&Base::foo) ; python::class_<OtherDerived,python::bases<Base> >( "OtherDerived",python::no_init) ; python::def("get_base",python::return_value_policy<python::manage_new_object>()); python::def("get_other_base",&get_other_base,python::return_value_policy<python::manage_new_object>()); }
互动用途:
>>> import example >>> b = example.get_base() >>> b.foo() 42 >>> b = example.get_other_base() >>> b.foo() Traceback (most recent call last): File "<stdin>",in <module> AttributeError: 'OtherDerived' object has no attribute 'foo'