Hi, > Thank you for the reply. > It compiles but same error on execution.
If I change the A2 exposure to bp::class_<A2, boost::shared_ptr<A2>, boost::noncopyable>("A2", bp::no_init) ... then f1() successfully returns a B2 object. But of course we then lose the Python-callback abilities provided by the wrapper class. Looking into the Boost.Python tests i stumbled across shared_ptr.cpp which contains: ... // This is the ugliness required to register a to-python converter // for shared_ptr<A>. objects::class_value_wrapper< shared_ptr<A> , objects::make_ptr_instance<A, objects::pointer_holder<shared_ptr<A>,A> > >(); ... So, giving this a try - looks like the following seems to be a working version for your sample (note that I changed the extension module name to shared_ptr_hierarchy in my code): C++ (wrapper) code: ================== #include <boost/python.hpp> namespace bp = boost::python; struct A2 { virtual ~A2(){} virtual int ret() =0; }; struct B2: public A2 { virtual ~B2(){} int ret() { return 1; } }; // wrapper struct A2Wrap : A2, bp::wrapper<A2> { inline int ret() { return this->get_override("ret")(); } }; // To the best of my knowledge we need to add callback support // through a wrapper class at every level of the hierarchy, so // a bit of code duplication going on. This is due to the fact // that B2 has no inheritance relation whatsoever to A2Wrap. // I haven't so far found an elegant/short solution for this // (e.g. using templates or macros) struct B2Wrap : B2, bp::wrapper<B2> { inline int ret() { if (bp::override py_override = this->get_override("ret")) { return py_override(); } return B2::ret(); } inline int default_ret() { return B2::ret(); } }; // function to map boost::shared_ptr<A2> f1() { return boost::shared_ptr<A2>(new B2()); } // invoke overridden virtual from C++ side (check callback-ability) int invoke_ret(A2 & a2) { return a2.ret(); } // expose to python BOOST_PYTHON_MODULE(shared_ptr_hierarchy) { bp::class_<A2Wrap, boost::shared_ptr<A2Wrap>, boost::noncopyable>("A2") .def("ret", bp::pure_virtual(&A2::ret)) ; // taken from boost.python libs/python/test/shared_ptr.cpp: // This is the ugliness required to register a to-python converter // for shared_ptr<A>. bp::objects::class_value_wrapper< boost::shared_ptr<A2> , bp::objects::make_ptr_instance<A2, bp::objects::pointer_holder<boost::shared_ptr<A2>,A2> > >(); bp::class_<B2Wrap, boost::shared_ptr<B2Wrap>, bp::bases<A2>, boost::noncopyable >("B2") .def("ret", &B2::ret, &B2Wrap::default_ret) ; bp::def("f1", f1); bp::def("invoke_ret", &invoke_ret, (bp::arg("a2"))); } Python test code: ================= import shared_ptr_hierarchy class PyB2(shared_ptr_hierarchy.A2): def ret(self): print "PyB2 Python class", self return 5 class PyC2(shared_ptr_hierarchy.B2): def ret(self): print "PyC2 Python class", self return 6 def invoke(factory): print "\nfactory:", factory obj = factory() print "obj =", obj print "obj.ret() ->", obj.ret() if hasattr(shared_ptr_hierarchy, 'invoke_ret'): print "shared_ptr_hierarchy.invoke_ret(obj) ->", \ shared_ptr_hierarchy.invoke_ret(obj) try: invoke(shared_ptr_hierarchy.A2) except Exception as e: print "Exception:", e invoke(shared_ptr_hierarchy.B2) invoke(shared_ptr_hierarchy.f1) invoke(PyB2) invoke(PyC2) Test code output: ================= factory: <class 'shared_ptr_hierarchy.A2'> obj = <shared_ptr_hierarchy.A2 object at 0x17cb5d0> obj.ret() -> Exception: Pure virtual function called factory: <class 'shared_ptr_hierarchy.B2'> obj = <shared_ptr_hierarchy.B2 object at 0x17cb628> obj.ret() -> 1 shared_ptr_hierarchy.invoke_ret(obj) -> 1 factory: <Boost.Python.function object at 0x177a460> obj = <shared_ptr_hierarchy.B2 object at 0x17d0668> obj.ret() -> 1 shared_ptr_hierarchy.invoke_ret(obj) -> 1 factory: <class '__main__.PyB2'> obj = <__main__.PyB2 object at 0x17cb628> obj.ret() -> PyB2 Python class <__main__.PyB2 object at 0x17cb628> 5 shared_ptr_hierarchy.invoke_ret(obj) -> PyB2 Python class <__main__.PyB2 object at 0x17cb628> 5 factory: <class '__main__.PyC2'> obj = <__main__.PyC2 object at 0x17cb628> obj.ret() -> PyC2 Python class <__main__.PyC2 object at 0x17cb628> 6 shared_ptr_hierarchy.invoke_ret(obj) -> PyC2 Python class <__main__.PyC2 object at 0x17cb628> 6 I can't really say that I understand why that's needed, but alas... Open issues: - Would be nice to have the abstract class A2 not being initializable from Python, but we can't use bp::no_init and inherit from A2 in Python because the Python-derived needs to call the (A2) base class constructor Holger Landesbank Baden-Wuerttemberg Anstalt des oeffentlichen Rechts Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz HRA 12704 Amtsgericht Stuttgart _______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org https://mail.python.org/mailman/listinfo/cplusplus-sig