Hi all,<br><br>I'm new to boost::python, and I need to write a program that defines<br>an abstract base class in C++, and a derived class in Python. Then I<br>want to instantiate the derived class in python and store its address<br>
in a C++ variable of type pointer to the base type and call python<br>methods in the derived type polymorphically from C++. All of that<br>works. The remaining problem is how to let the python function return<br>arbitrary python objects to C++, and have C++ hold a pointer to the<br>
arbitrary returned result. Below is my code so far, it isn't working<br>as written (but when I change all the 'PyObject *' to C++ type string and make<br>other appropriate changes in the python file, it works for returning<br>
string types. Can anyone give me an idea what changes are required in<br>the code to do what I need ?<br><br>Thanks,<br><br>Ambrose<br><br>The two files are included below:<br><br>mymodule.cpp ----------------------------------------------------------------------------------------<br>
<br>#include <iostream><br>#include <fstream><br>#include <string><br>using namespace std;<br><br>#include <boost/python.hpp><br>using namespace boost::python;<br><br>struct Base <br>{<br> Base() { s = Py_None; }<br>
Base(PyObject *input){ s = input; }<br> virtual ~Base() {}<br> virtual PyObject *run() { return s; }<br>private:<br> PyObject *s;<br>};<br><br>struct BaseWrap : Base, wrapper<Base><br>{<br> BaseWrap() : Base() {}<br>
BaseWrap(PyObject *input) : Base(input) {}<br><br> PyObject *run() {<br> if (override run = this->get_override("run"))<br> return run();<br> return Base::run();<br> }<br><br> PyObject *default_run() {<br>
return this->Base::run();<br> }<br>};<br><br>typedef boost::shared_ptr<Base> BasePtr;<br><br>BasePtr g(new Base);<br><br>BasePtr get_g() {<br> return g;<br>}<br><br>BasePtr set_g(BasePtr input_g) {<br> BasePtr tmp;<br>
tmp = g;<br> g = input_g;<br> return tmp;<br>}<br><br>PyObject *run_g() {<br> PyObject *tmp;<br> tmp = g->run();<br> return tmp;<br>}<br><br>BOOST_PYTHON_MODULE(mymodule) {<br> <br> def("set_g", set_g);<br>
def("get_g", get_g);<br> def("run_g", run_g);<br><br> class_<BaseWrap, boost::noncopyable>("Base", init<>()) <br> .def(init<PyObject *>())<br> .def("run", &Base::run, &BaseWrap::default_run)<br>
;<br><br> register_ptr_to_python< BasePtr >();<br><br>}<br><br>----- test.py ----------------------------------------------------------------------------------------------------<br>#!/usr/bin/env python<br><br>
from mymodule import *<br> <br>class DerivedS( Base ):<br> def run( self ):<br> x = Base.run( self )<br> return x+x<br><br>class DerivedM( Base ):<br><br> def __init__( self ):<br> import random<br>
x = random.randint(0,4)<br> if x == 0:<br> self.x = 1 # int<br> elif x == 1:<br> self.x = 1.0<br> elif x == 2:<br> self.x = 'string'<br> elif x == 3:<br>
self.x = ['array']<br> elif x == 4:<br> self.x = ('tuple')<br><br> def run( self ):<br> return self.x + self.x # defined for all 5 types above<br><br># minimal set of tests:<br>
<br>b1 = Base()<br>set_g(b1)<br>x = b1.run() # test from python should print nothing<br>y = run_g() # test call from C++ should print nothing<br>if x is None: print 'x is None'<br>if y is None: print 'y is None'<br>
<br>b2 = Base('init_str')<br>ib1 = set_g(b2) # want something identical to b1<br>b2.run() # want 'init_str'<br>run_g() # want 'init_str'<br><br>ds = DerivedS('derived')<br>ib2 = set_g(ds) # want something identical to b2<br>
ds.run() # want 'derivedderived'<br>run_g() # want 'derivedderived'<br><br>dm = DerivedM()<br>ids = set_g(dm) # want something identical to ds<br>dm.run() # want one of the values<br>
# 2, 2.0, 'stringstring', ['array','array'], ('tuple','tuple')<br>run_g() # same output as previous<br><br><br>