mirror of
https://github.com/pybind/pybind11.git
synced 2026-04-20 14:59:27 +00:00
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.
This commit is contained in:
@@ -619,27 +619,19 @@ interspersed with alias types and holder types (discussed earlier in this
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user