[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