Allow passing base types as a template parameter

This allows a slightly cleaner base type specification of:

    py::class_<Type, Base>("Type")

as an alternative to

    py::class_<Type>("Type", py::base<Base>())

As with the other template parameters, the order relative to the holder
or trampoline types doesn't matter.

This also includes a compile-time assertion failure if attempting to
specify more than one base class (but is easily extendible to support
multiple inheritance, someday, by updating the class_selector::set_bases
function to set multiple bases).
This commit is contained in:
Jason Rhinelander
2016-09-06 12:27:00 -04:00
parent 5fffe200e3
commit 6b52c838d7
9 changed files with 76 additions and 40 deletions

View File

@@ -185,9 +185,10 @@ inheritance relationship:
std::string bark() const { return "woof!"; }
};
There are two different ways of indicating a hierarchical relationship to
pybind11: the first is by specifying the C++ base class explicitly during
construction using the ``base`` attribute:
There are three different ways of indicating a hierarchical relationship to
pybind11: the first specifies the C++ base class as an extra template
parameter of the :class:`class_`; the second uses a special ``base`` attribute
passed into the constructor:
.. code-block:: cpp
@@ -195,6 +196,12 @@ construction using the ``base`` attribute:
.def(py::init<const std::string &>())
.def_readwrite("name", &Pet::name);
// Method 1: template parameter:
py::class_<Dog, Pet /* <- specify C++ parent type */>(m, "Dog")
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
// Method 2: py::base attribute:
py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
@@ -208,11 +215,12 @@ Alternatively, we can also assign a name to the previously bound ``Pet``
pet.def(py::init<const std::string &>())
.def_readwrite("name", &Pet::name);
// Method 3: pass parent class_ object:
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
Functionality-wise, both approaches are completely equivalent. Afterwards,
Functionality-wise, all three approaches are completely equivalent. Afterwards,
instances will expose fields and methods of both types:
.. code-block:: pycon