Monday, September 22, 2008

Boost Python - Abstract Classes

In the previous article I covered setting up Boost Python to work in Visual Studio.

In this article were going to get into a bit more detail of describing the bindings of classes. Specifically were going to deal with abstract classes and polymorphism.

Consider the following:

struct AbstractClass {
virtual std::string speak() const = 0;

struct DerivedClassA : AbstractClass {
virtual std::string speak() const {return "Derived Class A";}

struct DerivedClassB : AbstractClass {
virtual std::string speak() const {return "Derived Class B";}

We have an Abstract Class and two derived class that implement the speak method. How do we model this in Boost Python such that in Python we can get a pointer to one of these objects and call speak on the proper derived class.

To do this we have to build a wrapper class:

struct WrapperClass : AbstractClass , boost::python::wrapper<AbstractClass> { 
virtual std::string speak() const {
return this->get_override("speak")();

This wrapper class extends the AbstractClass, and extends a special boost::python::wrapper. For each virtual method you wrap it and call it with this->get_override().

Lastly you need to define the bindings for Python, this is similar to the Hello World example in article one:

using namespace boost::python;
def("getDerivedClassA",&getDerivedClassA,return_value_policy< manage_new_object >());
def("getDerivedClassB",&getDerivedClassB,return_value_policy< manage_new_object >());
class_<WrapperClass, boost::noncopyable > ("DerivedClass")


Here we added two test methods called getDerivedClassA and getDerivedClassB these will be in the package PyHelloWorld as dictated by 'BOOST_PYTHON_MODULE(PyHelloWorld)'

Lastly we want to be able to execute python in the same process as our executable. If you followed the instructions in part 1 then you simply need to add this method:

void start( ) {        
using namespace boost::python;
// Explicitly call the method that the BOOST_PYTHON_MODULE macro created.
// This sets up our DLL to be used by python.
std::string pythonCommand;
try {
PyRun_SimpleString("import PyHelloWorld");
while(1) {
std::cout << ">>> ";
if (pythonCommand == "quit") {
}else {
std::cout << PyRun_SimpleString(pythonCommand.c_str());
} catch ( error_already_set ) {

So now lets try it:

>>> import PyHelloWorld
0>>> a = PyHelloWorld.getDerivedClassA()
0>>> b = PyHelloWorld.getDerivedClassB()
0>>> print a.speak()
Derived Class A
0>>> print b.speak()
Derived Class B

No comments: