Support multiple inheritance from python
This commit allows multiple inheritance of pybind11 classes from
Python, e.g.
class MyType(Base1, Base2):
def __init__(self):
Base1.__init__(self)
Base2.__init__(self)
where Base1 and Base2 are pybind11-exported classes.
This requires collapsing the various builtin base objects
(pybind11_object_56, ...) introduced in 2.1 into a single
pybind11_object of a fixed size; this fixed size object allocates enough
space to contain either a simple object (one base class & small* holder
instance), or a pointer to a new allocation that can contain an
arbitrary number of base classes and holders, with holder size
unrestricted.
* "small" here means having a sizeof() of at most 2 pointers, which is
enough to fit unique_ptr (sizeof is 1 ptr) and shared_ptr (sizeof is 2
ptrs).
To minimize the performance impact, this repurposes
`internals::registered_types_py` to store a vector of pybind-registered
base types. For direct-use pybind types (e.g. the `PyA` for a C++ `A`)
this is simply storing the same thing as before, but now in a vector;
for Python-side inherited types, the map lets us avoid having to do a
base class traversal as long as we've seen the class before. The
change to vector is needed for multiple inheritance: Python types
inheriting from multiple registered bases have one entry per base.
diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst
index b6e0a2f..5617a4c 100644
--- a/docs/advanced/classes.rst
+++ b/docs/advanced/classes.rst
@@ -619,27 +619,19 @@
document)---pybind11 will automatically find out which is which. The only
requirement is that the first template argument is the type to be declared.
-There are two caveats regarding the implementation of this feature:
+It is also permitted to inherit multiply from exported C++ classes in Python,
+as well as inheriting from multiple Python and/or pybind-exported classes.
-1. When only one base type is specified for a C++ type that actually has
- multiple bases, pybind11 will assume that it does not participate in
- multiple inheritance, which can lead to undefined behavior. In such cases,
- add the tag ``multiple_inheritance``:
+There is one caveat regarding the implementation of this feature:
- .. code-block:: cpp
+When only one base type is specified for a C++ type that actually has multiple
+bases, pybind11 will assume that it does not participate in multiple
+inheritance, which can lead to undefined behavior. In such cases, add the tag
+``multiple_inheritance`` to the class constructor:
- py::class_<MyType, BaseType2>(m, "MyType", py::multiple_inheritance());
+.. code-block:: cpp
- The tag is redundant and does not need to be specified when multiple base
- types are listed.
+ py::class_<MyType, BaseType2>(m, "MyType", py::multiple_inheritance());
-2. As was previously discussed in the section on :ref:`overriding_virtuals`, it
- is easy to create Python types that derive from C++ classes. It is even
- possible to make use of multiple inheritance to declare a Python class which
- has e.g. a C++ and a Python class as bases. However, any attempt to create a
- type that has *two or more* C++ classes in its hierarchy of base types will
- fail with a fatal error message: ``TypeError: multiple bases have instance
- lay-out conflict``. Core Python types that are implemented in C (e.g.
- ``dict``, ``list``, ``Exception``, etc.) also fall under this combination
- and cannot be combined with C++ types bound using pybind11 via multiple
- inheritance.
+The tag is redundant and does not need to be specified when multiple base types
+are listed.