I have a Base
and a Derived
class in C++ for which I create Python-bindings with pybind11
. The base class implements a function (__repr__
) in which I want to access the runtime type name of self
. However, the way I do it, it just provides me the base type:
class Base {};
class Derived : public Base {};
PYBIND11_MODULE(mwe, m) {
py::class_<Base>(m, "Base")
.def("__repr__", [](const Base& self) {
// want to see the runtime type (i.e. most derived)
// of the `self` object!
return py::type::of(py::cast(self)).attr("__name__");
});
py::class_<Derived, Base>(m, "Derived")
.def(py::init<>());
}
In Python:
from mwe import Base, Derived
print(Derived()) # returns "Base", not "Derived"
How would I access the runtime type of self
instead?
The second look into the documentation gave me the right hint:
In C++, a type is only considered polymorphic if it has at least one virtual function and pybind11 will automatically recognize this
(see https://pybind11.readthedocs.io/en/stable/classes.html).
That means in my case Derived
is a non-polymorphic type behind a Base
pointer, such that Python just sees the Base
.
One way to fix this would be to add a virtual function to Base
to achieve actual polymorphism, e.g.:
class Base {
virtual ~Base() = default;
};
However, this is a change on the implementation and I still wonder whether one could achieve the intended behavior without changing Base
or Derived
.