mirror of
https://github.com/pybind/pybind11.git
synced 2026-04-20 06:49:25 +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:
@@ -81,6 +81,28 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
/// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
|
||||
/// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
|
||||
/// large holder type.
|
||||
template <typename T> class huge_unique_ptr {
|
||||
std::unique_ptr<T> ptr;
|
||||
uint64_t padding[10];
|
||||
public:
|
||||
huge_unique_ptr(T *p) : ptr(p) {};
|
||||
T *get() { return ptr.get(); }
|
||||
};
|
||||
|
||||
class MyObject5 { // managed by huge_unique_ptr
|
||||
public:
|
||||
MyObject5(int value) : value{value} {
|
||||
print_created(this);
|
||||
}
|
||||
int value;
|
||||
~MyObject5() {
|
||||
print_destroyed(this);
|
||||
}
|
||||
};
|
||||
|
||||
/// Make pybind aware of the ref-counted wrapper type (s)
|
||||
|
||||
// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
|
||||
@@ -89,6 +111,7 @@ private:
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); // Not required any more for std::shared_ptr,
|
||||
// but it should compile without error
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
|
||||
|
||||
// Make pybind11 aware of the non-standard getter member function
|
||||
namespace pybind11 { namespace detail {
|
||||
@@ -184,6 +207,10 @@ test_initializer smart_ptr([](py::module &m) {
|
||||
.def(py::init<int>())
|
||||
.def_readwrite("value", &MyObject4::value);
|
||||
|
||||
py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
|
||||
.def(py::init<int>())
|
||||
.def_readwrite("value", &MyObject5::value);
|
||||
|
||||
py::implicitly_convertible<py::int_, MyObject1>();
|
||||
|
||||
// Expose constructor stats for the ref type
|
||||
|
||||
Reference in New Issue
Block a user