在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公开
尝试了上述代码,但未能编译。
更新:编译错误:
/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.Pathon教程给出了如何公开纯虚拟函数的示例。简而言之,当用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_
文件规定:
模板参数:
T
:正在包装的类HeldType
:指定实际嵌入到包装T
实例的Python对象中的类型[…]。默认为T
因此,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类型从中派生,从而有效地防止重写。此外,Derived
在C++中实现Base::foo()
的实现细节无关紧要。如果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", &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'
抽象类实际上CAN在没有包装的情况下暴露给Boost.Python。诀窍是使用boost::noncopyable定义类,并避免使用pure_virtual方法包装器。
以下是更正后的代码(使用Boost.Python1.47.0和Python2.7.6测试):
#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
#include <boost/python/module.hpp>
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)
{
namespace py = boost::python;
py::class_<Base, boost::noncopyable>("Base", py::no_init)
.def("foo", &Base::foo);
py::def("get_base", get_base,
py::return_value_policy<py::reference_existing_object>()); //ignore mem leak
}
测试:
$ python
Python 2.7.6 (default, Mar 31 2014, 16:04:58)
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import libTestMod
>>> base = libTestMod.get_base()
>>> print base.foo()
42
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- Visual C++GC接口如何启用它以及要包含哪个库
- Windows.h与GLFW.h的接口
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- 提供与TMP和SFINAE的通用接口
- 为重写std::exception的库生成swig接口时出错
- 内联如何影响模块接口中的成员函数
- COM 接口 c# 封送数组数组
- 如何在 SCIP C++ 接口中获取 MILP 约束矩阵中的系数值
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如何绑定 C++ gRPC 客户端的网络接口
- 模板化接口 - 创建一个泛型模板类以返回任何容器
- 如何从实现接口的模板化类实例访问结构
- 带有进度表的 curl 多接口程序
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 我可以在具有一个标头和一个接口的 cpp 文件中有多个嵌入吗?
- 类接口,可以创建N个方法
- 类具有相同的接口,但参数的类型不同
- 如何与 Cheerp/js 中的 extern 变量接口?
- 如何使用现代 CMake 安装捆绑的接口依赖项?