在Boost Python中公开C ++接口 [英] Exposing C++ interface in boost python
问题描述
示例代码说明:
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
尝试了以上代码,但无法编译.
Tried the above code but fails to compile.
更新: 编译错误:
/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
Abstract C++ classes cannot be exposed in this manner to Boost.Python. The Boost.Python tutorial gives examples as to how to expose pure virtual functions. In short, when decorating methods with boost::python::pure_virtual
, a wrapper type needs to be created to allow C++ to polymorphic resolve the virtual function, and the virtual function implementation will delegate resolving the function polymorphically in the Python object's hierarchy.
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_
文档状态:
For details, when a type is exposed via boost::python::class_
, HeldType
defaults to the type being exposed, and the HeldType
is constructed within a Python object. The class_
documentation states:
模板参数:
-
T
:正在包装的类 -
HeldType
:指定包装在T
实例[...]中的Python对象中实际嵌入的类型.默认为T
.
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
是抽象类.
Hence, the boost::python::class_<Base>
will fail, because T = Base
and HeldType = Base
, and Boost.Python will try to instantiate an object of HeldType
into a Python object that represents an instance of Base
. This instantiation will fail as Base
is an abstract class.
这是一个完整的示例,显示了BaseWrap
类的使用.
Here is a complete example showing the use of a BaseWrap
class.
#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::no_init
)和不可复制(boost::noncopyable
)的情况下公开Boost.Python中的抽象类.缺少初始化器会阻止从其派生Python类型,从而有效地防止覆盖.此外,由Derived
在C ++中实现Base::foo()
的实现细节是无关紧要的.如果Python根本不了解foo()
方法,请省略通过def()
公开它.
It is possible to expose an abstract class in Boost.Python by exposing it with no default initializer (boost::python::no_init
) and non-copyable (boost::noncopyable
). The lack of an initializer prevents Python types from deriving from it effectively preventing overriding. Additionally, the implementation detail that Base::foo()
is implemented within C++ by Derived
is inconsequential. If Python should not know about a foo()
method at all, then omit exposing it via 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", &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>", line 1, in <module>
AttributeError: 'OtherDerived' object has no attribute 'foo'
这篇关于在Boost Python中公开C ++接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!