How to derive from an abstract base class
Dear all, I am totally new to Boost.Python, and I am going through the tutorial to get up to speed. I apologize if this is a very obvious question. Imagine I have a base class in C++ that I want to derive from both in C++ and in Python. The following code works wonderfully well: #include <boost/python.hpp> using namespace boost::python; class Base { public: virtual int f() {return -1;} }; class Derived : public Base { public: int f() {return 1;} }; class BaseWrap : public Base, public wrapper<Base> { public: int f() { if (override f = this->get_override("f")) return f(); return Base::f(); } int default_f() {return this->Base::f();} }; int func(Base& b) { return b.f(); } BOOST_PYTHON_MODULE(foo) { class_<Base> ("Base"); class_<Derived, bases<Base> > ("Derived") .def("f", &Derived::f); class_<BaseWrap, boost::noncopyable>("Base") .def("f", &Base::f, &BaseWrap::default_f); def("func", func, "Calls the method f of its argument"); } With this code, I can do the following:
import foo d1=foo.Derived() class D(foo.Base): ... def f(self): return 2 ... d2=D() foo.func(d1) 1 foo.func(d2) 2
So far so good. Now I would like to make Base::f a pure virtual function, and I can't get it to work. 1. Attempt: class Base { public: virtual int f() = 0; }; class Derived : public Base { public: int f() {return 1;} }; class BaseWrap : public Base, public wrapper<Base> { public: int f() {return this->get_override("f")();} }; int func(Base& b) { return b.f(); } BOOST_PYTHON_MODULE(foo) { class_<Derived, bases<Base> > ("Derived") .def("f", &Derived::f); class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)); def("func", func, "Calls the method f of its argument"); } This compiles, but when I try to import the resulting module I get he following error message: RuntimeError: extension class wrapper for base class Base has not been created yet This makes sense, because the Python side doesn't now about the abstract C++ class Base yet. Therefore… 2. Attempt: I change the wrapping code to the following: BOOST_PYTHON_MODULE(foo) { class_<Derived> ("Derived") .def("f", &Derived::f); class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)); def("func", func, "Calls the method f of its argument"); } Again this compiles, but I cannot call the c++ function func with the C++ class Derived anymore:
import foo d1=foo.Derived() foo.func(d1) Traceback (most recent call last): File "<stdin>", line 1, in <module> Boost.Python.ArgumentError: Python argument types in foo.func(Derived) did not match C++ signature: func(Base {lvalue})
Apparently the Python side doesn't know anymore that the C++ class Derived is derived from Base. The core of the problem seems to be that I cannot expose the abstract base class Base directly to Python, but only the wrapper class BaseWrap. But then C++ classes derived from Base and Python classes derived from BaseWrap do not have a common ancestor in the class hierarchy. If anyone could point me in the right direction, it would much appreciated. Best, Lutz
On 07/23/2010 03:09 PM, Lutz Maibaum wrote:
Dear all,
I am totally new to Boost.Python, and I am going through the tutorial to get up to speed. I apologize if this is a very obvious question.
<snip>
class Base { public: virtual int f() = 0; }; class Derived : public Base { public: int f() {return 1;} }; class BaseWrap : public Base, public wrapper<Base> { public: int f() {return this->get_override("f")();} };
int func(Base& b) { return b.f(); }
BOOST_PYTHON_MODULE(foo) { class_<Derived, bases<Base> > ("Derived") .def("f",&Derived::f); class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)); def("func", func, "Calls the method f of its argument"); }
Try this: BOOST_PYTHON_MODULE(foo) { class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)); class_<Derived, bases<Base> > ("Derived") .def("f",&Derived::f); def("func", func, "Calls the method f of its argument"); } (just swap the order of the class_ statements) Jim Bosch
On Jul 23, 2010, at 3:55 PM, Jim Bosch wrote:
Try this:
BOOST_PYTHON_MODULE(foo) { class_<BaseWrap, boost::noncopyable>("Base") .def("f", pure_virtual(&Base::f)); class_<Derived, bases<Base> > ("Derived") .def("f",&Derived::f); def("func", func, "Calls the method f of its argument"); }
(just swap the order of the class_ statements)
Fantastic! That works like charm. Thank you very much, Lutz
participants (2)
-
Jim Bosch -
Lutz Maibaum