Boost logo

Boost :

From: John Hunter (jdhunter_at_[hidden])
Date: 2001-08-20 11:38:54


>>>>> "John" == John Hunter <jdhunter_at_[hidden]> writes:

    John> I have a pure virtual abstract base class with no default
    John> constructor, ie, it handles some data for its derived
    John> classes but also has pure virtual methods. boost::python
    John> appears to reject such classes. For example, the following
    John> code fails to compile in boost::python.

Ok, the solution is simple. Just don't expose the constructor to
python. There is no reason to do so (and it is illegal!) since you
cannot create an instance of Base (Base's constructor should be
protected in the example in the OP). You can still expose all of
Base's member functions to python and use them through instances of
derived classes. This is all fairly obvious.... (now)

I notice that it is possible for Base to expose a regular function and
have derived classes use it (as in 'get' in the example below), but
for the special member function __str__, the derived class needs to
expose this as well. Hmmm...

John Hunter

Corrected example from OP:

//g++ -shared -I/home/guest/jdhunter/c/lib/boost_1_23_0 -I/usr/local/include/python1.6 -fPIC -ftemplate-depth-21 -L.. -L/home/guest/jdhunter/c/src/boost_python/ test_pure.cpp -o my_module.so -lboost_python

#include <string>
#include <stringstream>

#include <boost/python/class_builder.hpp>

class Base {
public:
  virtual ~Base() {}
  virtual int get() const=0;
protected:
  Base(int i) : _i(i) {}
  int get_i() const {return _i; }
private:
  int _i;
};

struct Derived : Base {
  Derived( int i) : Base(i) {}
  virtual int get() const { return get_i(); }
};

int base_get(const Base& b) {
  return b.get();
}

std::string base_gets(const Base& b) {
  std::ostringstream oss;
  oss << base_get(b);
  return oss.str();
}

namespace python = boost::python;

BOOST_PYTHON_MODULE_INIT(my_module)
{
    try
    {
       python::module_builder my_module("my_module");

       python::class_builder<Base> base_class(my_module, "Base");
       //don't expose constructor
       base_class.def(base_get, "get");
       base_class.def(base_gets, "__str__");

       python::class_builder<Derived> derived_class(my_module, "Derived");
       derived_class.def(python::constructor<int>());
       derived_class.def(base_gets, "__str__"); //this is required
       derived_class.declare_base(base_class);

    }
    catch(...)
    {
       python::handle_exception(); // Deal with the exception for Python
    }
}

Python test code:
#!/usr/local/bin/python

from my_module import Derived

d = Derived(2.0)

print '%1.2f' % d.get() #using base def 'get' works here
print '%s' % d #using base def '__str__' alone doesn't work here


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk