以官网文为本,尽量翻译下,方便以后看。我使用的boost 版本为1.5.1 。原谅网址:http://www.boost.org/doc/libs/1_51_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.inheritance
Inheritance
继承
In the previous examples, we dealt with classes that are not polymorphic. This is not often the case. Much of the time, we will be wrapping polymorphic classes and class hierarchies related by inheritance. We will often have to write Boost.Python wrappers for classes that are derived from abstract base classes.
在前面的例子中,我们处理的类并不具备多态性,在实际情况中并不多。大多时候,我们会包装多态类和类的继承关系。我们也经常用boost.python包装从绝虚基类继承而来的类。
Consider this trivial inheritance structure:
看下面这个简单的继承结构:
struct Base { virtual ~Base(); }; struct Derived : Base {};
And a set of C++ functions operating on Base
and Derived
object instances:
并且一些c++函数操作这些Base类和Derived类的对象:
void b(Base*); void d(Derived*); Base* factory() { return new Derived; }
We've seen how we can wrap the base class Base
:
下面演示怎么封装基类:
class_<Base>("Base") /*...*/ ;
Now we can inform Boost.Python of the inheritance relationship between Derived
and its base class Base
. Thus:
现在我们可以告诉boost.python Derived类和它的基类Base之间的继承关系。因此:
class_<Derived, bases<Base> >("Derived") /*...*/ ;
Doing so, we get some things for free:
- Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
- If Base is polymorphic,
Derived
objects which have been passed to Python via a pointer or reference toBase
can be passed where a pointer or reference toDerived
is expected.
Now, we will expose the C++ free functions b
and d
and factory
:
现在我们会暴露c++ 函数 b , d 和factory:
def("b", b); def("d", d); def("factory", factory);
Note that free function factory
is being used to generate new instances of class Derived
. In such cases, we usereturn_value_policy<manage_new_object>
to instruct Python to adopt the pointer to Base
and hold the instance in a new Python Base
object until the the Python object is destroyed. We will see more of Boost.Python call policies later.
需要说明的是,自由函数 factory 用来制造Derived 类的对象。在这些例子中,我们使用 return_value_policy<manage_new_object> 告诉 Python 接收Base的指针,在Python的Base对象(即包装好的Python的Base类,和先前的C++的Base类不是一个类)中保存这个实例,直到这个Python 对被销毁。在Boost.Python 的 call policies 可以看到更多相关信息。
// Tell Python to take ownership of factory's result def("factory", factory, return_value_policy<manage_new_object>());
Class Virtual Functions
In this section, we will learn how to make functions behave polymorphically through virtual functions. Continuing our example, let us add a virtual function to our Base
class:
在这一部分中,我们将学习通过虚函数怎样实现多态性。继承我们的例子,现在给Base类添加一个虚函数:
struct Base { virtual ~Base() {} virtual int f() = 0; };
One of the goals of Boost.Python is to be minimally intrusive on an existing C++ design. In principle, it should be possible to expose the interface for a 3rd party library without changing it. It is not ideal to add anything to our class Base
. Yet, when you have a virtual function that's going to be overridden in Python and called polymorphically from C++, we'll need to add some scaffoldings to make things work properly. What we'll do is write a class wrapper that derives from Base
that will unintrusively hook into the virtual functions so that a Python override may be called:
Boost.Python的目标之一是最少化地减少对现在有的c++设计的更改。原则上讲,应该做到在给第三方库提供接口里不更改原有设计。对Base类添加任何代码都是不理想的。还有,当有一个在Python中会被重写,并且从C++使用多态的虚函数时,我们必须添加一些辅助代码以保证程序的正常运行。我们需要做的就是从Base中新继承一个类(PS:通常应该是最后一个类,比如A为基类,B继承A,如果再继承A来封装,势必不能转为类B的对象),并封装它,这样就在不修改的同时给虚函数添加了一个钩,以使在Python中重写函数后也可调用:
struct BaseWrap : Base, wrapper<Base> { int f() { return this->get_override("f")(); } };
Notice too that in addition to inheriting from Base
, we also multiply- inherited wrapper<Base>
(See Wrapper). The wrapper
template makes the job of wrapping classes that are meant to overridden in Python, easier.
wrapper<Base>
(详见
Wrapper
). 这个wrapper template 使封装类,换句话说,在Python中重写虚函数变得更简单。
class BaseWrap : public Base, public wrapper<Base> {...};
BaseWrap's overridden virtual member function f
in effect calls the corresponding method of the Python object through get_override
.
BaseWrap 重写的虚函数 f 在运行时通过get_override(...) 调用相应的Python对象的方法。
Finally, exposing Base
:
最后,暴露 Base :
class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)) ;
pure_virtual
signals Boost.Python that the function f
is a pure virtual function.
pure_virtual符号 告诉 Boost.Python 函数 f 是纯虚函数。
![]() | Note 注意 |
---|---|
member function and methods 成员函数方法 Python, like many object oriented languages uses the term methods. Methods correspond roughly to C++'s member functions Python, 像许多面对对象语言使用方法,在c++中方法被称作成员函数。 |
Virtual Functions with Default Implementations
We've seen in the previous section how classes with pure virtual functions are wrapped using Boost.Python's class wrapper facilities. If we wish to wrap non-pure-virtual functions instead, the mechanism is a bit different.
在先前的章节中,我们学习了如何使用Boost.Python 类 wrapper 工具封装纯虚函数。如果我们想封装非纯虚函数,这个工作机制有一点不同。
Recall that in the previous section, we wrapped a class with a pure virtual function that we then implemented in C++, or Python classes derived from it. Our base class:
在先前的章节中,我们封装了有纯虚函数的c++类,或者继承于它的Python类。我们的基类:
struct Base { virtual int f() = 0; };
had a pure virtual function f
. If, however, its member function f
was not declared as pure virtual:
有一个纯虚函数f。然而,如果它的成员函数f不是声明为纯虚函数:
struct Base { virtual ~Base() {} virtual int f() { return 0; } };
We wrap it this way:
我们要这样封装它:
struct BaseWrap : Base, wrapper<Base> { int f() { if (override f = this->get_override("f")) return f(); // *note* return Base::f(); } int default_f() { return this->Base::f(); } };
Notice how we implemented BaseWrap::f
. Now, we have to check if there is an override for f
. If none, then we call Base::f()
.
BaseWrap::f
. 现在我们必须检查是否存在函数f的重写。如果没有,我们调用 Base::f()
.
Finally, exposing:
最后,这样提供接口:
class_<BaseWrap, boost::noncopyable>("Base") .def("f", &Base::f, &BaseWrap::default_f) ;
Take note that we expose both &Base::f
and &BaseWrap::default_f
. Boost.Python needs to keep track of 1) the dispatch function f
and 2) the forwarding function to its default implementation default_f
. There's a special def
function for this purpose.
注意我们同时暴露了&Base::f
and &BaseWrap::default_f
. Boost.Python 需要追踪 1)调度函数f 2)其默认实现的函数default_f 。为了达到这个目的,这里有一个特殊的def函数。
In Python, the results would be as expected:
在Python中,结果应该是这样的:
>>> base = Base() >>> class Derived(Base): ... def f(self): ... return 42 ... >>> derived = Derived()
Calling base.f()
:
>>> base.f() 0
Calling derived.f()
:
>>> derived.f() 42