@@ -2086,6 +2086,44 @@ declarations in generated :ref:`stubs <stubs>`,
20862086 Declares a callback that will be invoked when a C++ instance is first
20872087 cast into a Python object.
20882088
2089+ .. cpp :struct :: upcast_hook
2090+
2091+ .. cpp :function :: upcast_hook(void * (* hook)(PyObject*, const std::type_info*) noexcept )
2092+
2093+ Allow Python instances of the class being bound to be passed to C++
2094+ functions that expect a pointer to a subobject of that class.
2095+ Since nanobind only acknowledges at most one base class of each bound type,
2096+ the upcast hook can be helpful for providing some minimal emulation of
2097+ additional bases.
2098+
2099+ The hook receives a nanobind instance as its first argument and the
2100+ desired subobject type as its second. If it can make the cast, it
2101+ returns a pointer to something of the requested type; if not, it
2102+ returns nullptr.
2103+
2104+ **Example: **
2105+
2106+ .. code-block :: cpp
2107+
2108+ struct A { int a = 10; };
2109+ struct B { int b = 20; };
2110+ struct D : A, B { int d = 30; };
2111+
2112+ nb::class_<A>(m, "A").def_rw("a", &A::a);
2113+ auto clsB = nb::class_<B>(m, "B").def_rw("b", &B::b);
2114+
2115+ auto try_D_to_B = [](PyObject *self_py, const std::type_info *target) noexcept -> void* {
2116+ D *self = nb::inst_ptr<D>(self_py);
2117+ if (*target == &typeid(B)) {
2118+ return static_cast<B*>(self);
2119+ }
2120+ return nullptr;
2121+ };
2122+
2123+ auto clsD = nb::class_<D, A>(m, "D", nb::upcast_hook(try_D_to_B))
2124+ .def_rw("d", &D::d);
2125+ clsD.attr("b") = clsB.attr("b");
2126+
20892127
20902128 .. _enum_binding_annotations :
20912129
0 commit comments