Subclassing C++ classes in Python
Hi there, I am creating binding for some C++ classes and I need to be able to subclass exposed C++ classes in Python (and pass subclassed instances back in to C++ code). I was able to make this work by following this example: http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/html/pytho... and creating binding for both: original C++ classes and ‘wrapper’ structs. This however create inconvenience and path for errors because now users need to remember to use different base class when subclassing C++ classes. Is there is a way to achieve subclassing functionality by exposing one class instead of two? When I tries to use class exposed as ’wrapper’ as substitute for C++ original class i am getting a segfault error (see example below). Is there is something wrong with a way i create a wrapper-class or it is not intended to work as substitute for a base class? Thanks, Ernie. Python code: ———————— from subclass import * class B(A_Wrapper): def __init__(self): A_Wrapper.__init__(self) def info(self): print 'B info!' a = A(); a.info(); print '1' b = B(); b.info(); print '2' aw = A_Wrapper(); print '3'; aw.info(); print '4' # <-- segfault before '4' got printed C++ code: ———————— #include <iostream> #include <boost/python.hpp> class A { public: virtual ~A() { std::cout << "A destructor for object: " << this << std::endl; } virtual void info() { std::cout << "C++ A info for object" << this << std::endl; } }; struct A_Wrapper : A, boost::python::wrapper<A> { A_Wrapper() : A() {} void info() {this->get_override("info")(); } }; BOOST_PYTHON_MODULE(subclass) { boost::python::class_<A, boost::noncopyable>("A") .def("info", &A::info) ; boost::python::class_<A_Wrapper, boost::noncopyable>("A_Wrapper", boost::python::init <>() ) .def("info", &A_Wrapper::info) ; }
Hi Ernie,
When I tries to use class exposed as ’wrapper’ as substitute for C ++ original class i am getting a segfault error (see example below). Is there is something wrong with a way i create a wrapper-class or it is not intended to work as substitute for a base class?
I haven't tried your code sample but you'd normally just expose the wrapper class *instead* of the original class, with the name of "A". Python users don't need to know about the wrapper class intricacies. If you expose a non-pure-virtual method you should also add the default implementation, just as you cited from http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/html/pytho... (necessary to avoid infinite recursion if your Python override implementation calls the C++ base class method) I.e. something like (untested! Stick closely to the tutorial if in doubt) #include <iostream> #include <boost/python.hpp> class A { public: virtual ~A() { std::cout << "A destructor for object: " << this << std::endl; } virtual void info() { std::cout << "C++ A info for object" << this << std::endl; } }; struct A_Wrapper : A, boost::python::wrapper<A> { void info( { if (override info_override = this->get_override("info")) { return info_override(); } return A::info(); } void default_info() { return this->A::info(); } }; BOOST_PYTHON_MODULE(subclass) { boost::python::class_<A_Wrapper, boost::noncopyable>("A", boost::python::init <>() ) .def("info", &A::info, &A_Wrapper::default_info) ; } So the wrapper class provides you with the callback-ability to Python and this is the one to expose. As per the segfault you get: I guess that this might stem from your not calling the boost::python::wrapper<A> base class constructor in your A_Wapper constructor (note how I didn't provide a constructor for the wrapper class): A_Wrapper() : A() {} // <-- not calling all base constructors here Again, haven't actually tried it. Holger Landesbank Baden-Wuerttemberg Anstalt des oeffentlichen Rechts Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz HRA 12704 Amtsgericht Stuttgart
Hi Holger, Adding checks for override and default implementation fixed the issue. - Thank you! Best, Ernie. On Mon, Mar 16, 2015 at 2:04 AM, Holger Joukl <Holger.Joukl@lbbw.de> wrote:
Hi Ernie,
When I tries to use class exposed as ’wrapper’ as substitute for C ++ original class i am getting a segfault error (see example below). Is there is something wrong with a way i create a wrapper-class or it is not intended to work as substitute for a base class?
I haven't tried your code sample but you'd normally just expose the wrapper class *instead* of the original class, with the name of "A".
Python users don't need to know about the wrapper class intricacies.
If you expose a non-pure-virtual method you should also add the default implementation, just as you cited from
http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/html/pytho... (necessary to avoid infinite recursion if your Python override implementation calls the C++ base class method)
I.e. something like (untested! Stick closely to the tutorial if in doubt)
#include <iostream> #include <boost/python.hpp>
class A { public: virtual ~A() { std::cout << "A destructor for object: " << this << std::endl; }
virtual void info() { std::cout << "C++ A info for object" << this << std::endl; } };
struct A_Wrapper : A, boost::python::wrapper<A> { void info( { if (override info_override = this->get_override("info")) { return info_override(); } return A::info(); }
void default_info() { return this->A::info(); } };
BOOST_PYTHON_MODULE(subclass) { boost::python::class_<A_Wrapper, boost::noncopyable>("A", boost::python::init <>() ) .def("info", &A::info, &A_Wrapper::default_info) ; }
So the wrapper class provides you with the callback-ability to Python and this is the one to expose.
As per the segfault you get: I guess that this might stem from your not calling the boost::python::wrapper<A> base class constructor in your A_Wapper constructor (note how I didn't provide a constructor for the wrapper class):
A_Wrapper() : A() {} // <-- not calling all base constructors here
Again, haven't actually tried it.
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
participants (2)
-
Ernie Lee -
Holger Joukl