[BUG] Problem when creating derived Python objects from C++ (inheritance slicing) · Issue #1333 · pybind/pybind11 (original) (raw)

EDIT(eric): Adding a tracking list.


Issue description

Hello,
Consider deriving a C++ class in Python and overloading virtual functions, including a 'Clone' function.
When passing a derived Python object to C++ without holding a reference (like calling Clone()), the information about the Python type is lost. In this case the wrong base-class function is called. More complex cases may result in a SEGFAULT.

Is there any way to work around/fix this without causing memory leaks?

Thanks!

Reproducible example code

test.cpp

// test.cpp #include <pybind11/pybind11.h> #include <Python.h>

#include #include

using std::cout; using std::endl; using std::unique_ptr; using std::shared_ptr; using std::make_shared;

namespace py = pybind11;

class Base { public: virtual void Print() { cout << "Base!" << endl; }

virtual shared_ptr<Base> Clone() {
    return make_shared<Base>();
}

};

class PyBase : public Base { public: using Base::Base; // Inherit constructors void Print() override { PYBIND11_OVERLOAD(void, Base, Print, ); } shared_ptr Clone() override { PYBIND11_OVERLOAD(shared_ptr, Base, Clone, ); } };

PYBIND11_MODULE(libtest, m) { py::class_<Base, py::wrapper, shared_ptr>(m, "Base") .def(py::init<>()) ;

m.def("Test", [] ( shared_ptr<Base> b ) {
      shared_ptr<Base> d = b->Clone();
      // Python object of d is already dead!
      d->Print();  // prints "Base!"
});

}

test.py

from libtest import *

class Derived(Base): def init(self): super().init()

def Print(self):
    print("Derived!")

def Clone(self):
    return Derived()

Test(Derived())