Boost.Python extension classes support single and multiple-inheritance in Python, just like regular Python classes. You can arbitrarily mix built-in Python classes with extension classes in a derived class' tuple of bases. Whenever a Boost.Python extension class is among the bases for a new class in Python, the result is an extension class:
>>> class MyPythonClass: ... def f(): return 'MyPythonClass.f()' ... >>> import my_extension_module >>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass): ... '''This is an extension class''' ... pass ... >>> x = Derived() >>> x.f() 'MyPythonClass.f()' >>> x.g() 'MyExtensionClass.g()'
Boost.Python also allows us to represent C++ inheritance relationships so that
wrapped derived classes may be passed where values, pointers, or
references to a base class are expected as arguments. The
declare_base
member function of
class_builder<>
is used to establish the relationship
between base and derived classes:
#include <memory> // for std::auto_ptr<> struct Base { virtual ~Base() {} virtual const char* name() const { return "Base"; } }; struct Derived : Base { Derived() : x(-1) {} virtual const char* name() const { return "Derived"; } int x; }; std::auto_ptr<Base> derived_as_base() { return std::auto_ptr<Base>(new Derived); } const char* get_name(const Base& b) { return b.name(); } int get_derived_x(const Derived& d) { return d.x; }
#include <boost/python/class_builder.hpp> // namespace alias for code brevity namespace python = boost::python; BOOST_PYTHON_MODULE_INIT(my_module) { python::module_builder my_module("my_module"); python::class_builder<Base> base_class(my_module, "Base"); base_class.def(python::constructor<>()); python::class_builder<Derived> derived_class(my_module, "Derived"); derived_class.def(python::constructor<>()); // Establish the inheritance relationship between Base and Derived derived_class.declare_base(base_class); my_module.def(derived_as_base, "derived_as_base"); my_module.def(get_name, "get_name"); my_module.def(get_derived_x, "get_derived_x"); }
Then, in Python:
objects of wrapped class Derived may be passed where Base is expected>>> from my_module import * >>> base = Base() >>> derived = Derived() >>> get_name(base) 'Base'
objects of wrapped class Derived can be passed where Derived is expected but where type information has been lost.>>> get_name(derived) 'Derived'
>>> get_derived_x(derived_as_base()) -1
If for some reason your base class has no virtual functions but you still want
to represent the inheritance relationship between base and derived classes,
pass the special symbol boost::python::without_downcast
as the 2nd parameter
to declare_base
:
struct Base2 {}; struct Derived2 { int f(); };
... python::class_builder<Base> base2_class(my_module, "Base2"); base2_class.def(python::constructor<>()); python::class_builder<Derived2> derived2_class(my_module, "Derived2"); derived2_class.def(python::constructor<>()); derived_class.declare_base(base_class, python::without_downcast);
This approach will allow Derived2
objects to be passed where
Base2
is expected, but does not attempt to implicitly convert (downcast)
smart-pointers to Base2
into Derived2
pointers,
references, or values.
Next: Special Method and Operator Support Previous: Function Overloading Up: Top
© Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
Updated: Nov 26, 2000