mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Allow specifying custom base classes
- Useful for object hierarchies that don't use C++ inheritance (such as GObject)
This commit is contained in:
parent
964c49978f
commit
d6df11602b
@ -65,6 +65,31 @@ struct base {
|
||||
base() = default;
|
||||
};
|
||||
|
||||
/** \rst
|
||||
Annotation indicating that a class should appear to python to derive from
|
||||
another given type. This is useful for wrapping type systems that don't
|
||||
utilize standard C++ inheritance.
|
||||
|
||||
You must provide a caster function that casts from the derived type to
|
||||
the base type. As an example, standard C++ inheritance would do this:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
py::class_<Derived> cls(m, "Derived", py::custom_base<Base>([](void *o) {
|
||||
return static_cast<Base*>(reinterpret_cast<Derived*>(o));
|
||||
}));
|
||||
|
||||
.. note:: This is an advanced feature. If you use this, you likely need
|
||||
to implement polymorphic_type_hook for your type hierarchy.
|
||||
\endrst */
|
||||
template <typename T> struct custom_base {
|
||||
using caster = void *(*)(void *);
|
||||
|
||||
explicit custom_base(const caster &f) : fn(f) {}
|
||||
caster fn;
|
||||
};
|
||||
|
||||
|
||||
/// Keep patient alive while nurse lives
|
||||
template <size_t Nurse, size_t Patient>
|
||||
struct keep_alive {};
|
||||
@ -551,6 +576,17 @@ struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
||||
static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
|
||||
};
|
||||
|
||||
/// Process a custom base attribute
|
||||
template <typename T>
|
||||
struct process_attribute<custom_base<T>> : process_attribute_default<custom_base<T>> {
|
||||
static void init(const custom_base<T> &b, type_record *r)
|
||||
{
|
||||
r->add_base(typeid(T), b.fn);
|
||||
// TODO: rename this to 'nonsimple'?
|
||||
r->multiple_inheritance = true;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a multiple inheritance attribute
|
||||
template <>
|
||||
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
||||
|
@ -125,6 +125,7 @@ set(PYBIND11_TEST_FILES
|
||||
test_const_name
|
||||
test_constants_and_functions
|
||||
test_copy_move
|
||||
test_custom_base
|
||||
test_custom_type_casters
|
||||
test_custom_type_setup
|
||||
test_docstring_options
|
||||
|
39
tests/test_custom_base.cpp
Normal file
39
tests/test_custom_base.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
tests/test_custom_base.cpp -- test custom type hierarchy support
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Base {
|
||||
int i = 5;
|
||||
};
|
||||
|
||||
struct Derived {
|
||||
int j = 6;
|
||||
|
||||
// just to prove the base can be anywhere
|
||||
Base base;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_SUBMODULE(custom_base, m) {
|
||||
|
||||
py::class_<Base>(m, "Base").def_readwrite("i", &Base::i);
|
||||
|
||||
py::class_<Derived>(m, "Derived", py::custom_base<Base>([](void *o) -> void * {
|
||||
return &reinterpret_cast<Derived *>(o)->base;
|
||||
})).def_readwrite("j", &Derived::j);
|
||||
|
||||
m.def("create_derived", []() { return new Derived; });
|
||||
m.def("create_base", []() { return new Base; });
|
||||
|
||||
m.def("base_i", [](Base *b) { return b->i; });
|
||||
|
||||
m.def("derived_j", [](Derived *d) { return d->j; });
|
||||
};
|
23
tests/test_custom_base.py
Normal file
23
tests/test_custom_base.py
Normal file
@ -0,0 +1,23 @@
|
||||
from pybind11_tests import custom_base as m
|
||||
|
||||
|
||||
def test_cb_base():
|
||||
b = m.create_base()
|
||||
|
||||
assert isinstance(b, m.Base)
|
||||
assert b.i == 5
|
||||
|
||||
assert m.base_i(b) == 5
|
||||
|
||||
|
||||
def test_cb_derived():
|
||||
d = m.create_derived()
|
||||
|
||||
assert isinstance(d, m.Derived)
|
||||
assert isinstance(d, m.Base)
|
||||
|
||||
assert d.i == 5
|
||||
assert d.j == 6
|
||||
|
||||
assert m.base_i(d) == 5
|
||||
assert m.derived_j(d) == 6
|
Loading…
Reference in New Issue
Block a user