Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.11.1
Problem description
Similar to #2351. Though I have overloaded functions defined in child classes, instead of the base class.
I have a base class with multiple child classes. The base class does has a (pure) virtual function (with 2 doubles as arguments). The child classes overload this function with more doubles as arguments, the amount depends on the child class.
The issue is that the (pure) virtual function func
is not inherited into the child classes. Only the overloaded version of the function is available in the child classes. The original function (2 doubles as arguments) is only available in the child classes when defining the function for each child. It doesn't matter whether I reference the base class or the child class in the definition. (See the commented lines in the child classes.) It also doesn't matter whether I use the py::overload_cast
in the base class or not. (See commented line in the base class.)
The __copy__
and __deepcopy__
functions are inherited from the base class to the child classes without any issue.
The bug: The overloaded (pure) virtual function is not inherited into the child classes unless defined in the child classes.
edit: I think the issue is not related to the virtual functions, but the overloading of base functions in the child classes. As a fully implemented non-virtual function (func2
) shows the same issue of not being inherited. Again only the overloaded version of the function is available.
Reproducible example code
mylib.hpp
class Base {
public:
Base()
virtual ~Base() = default;
virtual void func(double, double) = 0;
void func2(double);
};
class Child1: public Base {
public:
Child1();
void func(double, double, double, double);
void func2(double, double);
};
class Child2: public Base {
public:
Child2();
void func(double, double, double, double, double, double);
void func2(double, double, double);
};
mylib_pybind.cpp
template <class BaseType = Base>
class PyBase : public BaseType
{
using BaseType::BaseType; // Inherit constructors
BaseType* clone() const override
{
PYBIND11_OVERRIDE_PURE_NAME(BaseType*, BaseType, "__copy__", clone);
};
void func(double arg1, double arg2) override
{
PYBIND11_OVERRIDE_PURE_NAME(void, BaseType, "func", func, arg1, arg2);
};
};
template <class ChildType>
class PyChild : public PyBase<ChildType>
{
public:
using PyBase<ChildType>::PyBase; // Inherit constructors
ChildType* clone() const override
{
PYBIND11_OVERRIDE_NAME(ChildType*, ChildType, "__copy__", clone);
}
void func(double arg1, double arg2) override
{
PYBIND11_OVERRIDE_NAME(void, ChildType, "func", func, arg1, arg2);
};
};
PYBIND11_MODULE(mypkg, m) {
py::class_<Base, PyBase>(m, "Base")
.def(py::init<>())
.def("__copy__", &Base::clone)
.def("__deepcopy__", [](const Base& self, py::dict&) { return self.clone(); }, py::arg("memo"))
.def("func", &Base::func)
// .def("func", py::overload_cast<double, double>(&Base::func))
.def("func2", &Base::func2);
py::class_<Child1, Base, PyChild<Child1>>(m, "Child1")
.def(py::init<>())
// .def("func", py::overload_cast<double, double>(&Child1::func))
// .def("func", py::overload_cast<double, double>(&Base::func))
.def("func", py::overload_cast<double, double, double, double>(&Child1::func))
// .def("func2", py::overload_cast<double>(&Child1::func2))
// .def("func2", py::overload_cast<double>(&Base::func2))
.def("func2", py::overload_cast<double, double>(&Child1::func2));
py::class_<Child2, Base, PyChild<Child2>>(m, "Child2")
.def(py::init<>())
// .def("func", py::overload_cast<double, double>(&Child2::func))
// .def("func", py::overload_cast<double, double>(&Base::func))
.def("func", py::overload_cast<double, double, double, double, double, double>(&Child2::func))
// .def("func2", py::overload_cast<double>(&Child2::func2))
// .def("func2", py::overload_cast<double>(&Base::func2))
.def("func2", py::overload_cast<double, double, double>(&Child2::func2));
}
Is this a regression? Put the last known working version here if it is.
Not a regression