[C++-sig] How to derive from an abstract base class
Lutz Maibaum
lutz.maibaum at gmail.com
Sat Jul 24 00:09:53 CEST 2010
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
More information about the Cplusplus-sig
mailing list