views:

1682

answers:

2

Hello,

This is my code:

// c++ (main.cpp)
#include <vector>
#include <iostream>
#include <boost/python.hpp>
#include <boost/python/enum.hpp>
#include <boost/python/def.hpp>
#include <boost/python/module.hpp>

using namespace std;
using namespace boost;
using namespace boost::python;

class Base
{
public:
    Base(void) {}
virtual void f1(void) = 0;
virtual void f2(void) = 0;
};

class Stack
{
public:
Stack(void) {}
void push(Base *e)
{
 stack.push_back(e);
}
void pushPython(boost::python::object &o)
{
 Base &e = extract<Base &>(o) BOOST_EXTRACT_WORKAROUND;
 push(&e);
}
void test(void)
{
 for(std::vector<Base *>::iterator i = stack.begin(); i != stack.end(); i++)
 {
  (*i)->f1();
  (*i)->f2();
 }
}
private:
std::vector<Base *> stack;
};


class DerivedCPP : public Base
{
public:
DerivedCPP(void) {}
virtual void f1(void)
{
 std::cout << "DerivedCPP f1()" << std::endl;
}
virtual void f2(void)
{
 std::cout << "DerivedCPP f2()" << std::endl;
}
};

BOOST_PYTHON_MODULE(mytest)
{
boost::python::class_<Base,boost::noncopyable>("Base",boost::python::no_init)
 .def( "f1", &Base::f1)
 .def( "f2", &Base::f2)
 ;

boost::python::class_<DerivedCPP,bases<Base>>("DerivedCPP")
 .def( "f1", &DerivedCPP::f1)
 .def( "f2", &DerivedCPP::f2)
 ;

boost::python::class_<Stack>("Stack", boost::python::no_init)
 .def( "push", &Stack::pushPython)
 .def( "test", &Stack::test)
 ;
}

int main(int argc, char** argv)
{
PyImport_AppendInittab("mytest", &initmytest);
Py_Initialize();
boost::python::object main_module(( handle<>( borrowed( PyImport_AddModule( "__main__" )))));
boost::python::object main_namespace = main_module.attr("__dict__");
boost::python::object mytest( (handle<>(PyImport_ImportModule("mytest"))) );
main_namespace["mytest"] = mytest;
Stack *STACK = new Stack();
main_namespace["Stack"] = ptr(STACK);
Base *e = new DerivedCPP();
STACK->push(e);
STACK->test();
boost::python::object main = import("__main__");
boost::python::object global(main.attr("__dict__"));
boost::python::object result = exec_file("test.py", global, global);
Py_Finalize();
return 0;
}


# python (test.py)
print 'test.py'
print

class DerivedPython(mytest.Base):
def __init__(self):
 print "DerivedPython __init__()"
def f1(self):
 print "DerivedPython f1()"
def f2(self):
 print "DerivedPython f2()"

print 'DerivedPython()'
p = DerivedPython()
p.f1()
p.f2()

print 'mytest.DerivedCPP()'
c = mytest.DerivedCPP()
c.f1()
c.f2()

print 'Stack.push(c)'
Stack.push(c)
print 'OK'

print "Stack.test()"
Stack.test()

print 'Stack.push(p)'
Stack.push(p) # crash!
print 'OK'

print "Stack.test()"
Stack.test()

I want to make python class derived from c++ abstract class and then pass this object back to c++. How should I do that without crash?

+2  A: 

It's a little complicated, but not difficult. Read this page, it should give you everything you need.

You need to wrap the abstract class like this:

struct BaseWrap : Base, wrapper<Base>
{
    void f1()
    {
        this->get_override("f1")();
    }

    void f2()
    {
        this->get_override("f2")();
    }

};

Then you have to expose Base as follows:

class_<BaseWrap, boost::noncopyable>("Base")
    .def("f1", pure_virtual(&Base::f1))
    .def("f2", pure_virtual(&Base::f2))
    ;
Moe
Hey, do you know how to wrap if pure virtual f1 and f2 recieve arguments? I can't find it anywhere googling :(
Fabzter
I don't have any working code in front of me (I no longer work where I did when I wrote this answer), but you should just declare your method with arguments, and then pass those arguments to the call - something like: void f1(int x, float y) { this->get_override("f1")(x, y); }
Moe
A: 

You might also want to check out the Py++ package. It's a utility used for parsing C++ code, and generating boost::python wrappers for that code. I've only tried it a little, but it seems to handle automatically creating base class wrappers and things like that (and according to the docs, the author was able to export several boost libraries and run their test suites in Python by generating bindings via Py++).

Magnus Österlind