In [1]:
from ROOTaaS.iPyROOT import ROOT
To bridge between the C++ and Python virtual functions we need to define a proper C++ class that will forward the virtual function calls to the the Python object. The only trick here is that this C++ class needs to have a constructor to receive the self from the Python object for use afterwords.
The implemetation is done completely in C++ with the next block.
In [2]:
%%dcl
#include "TObject.h"
#include "Python.h"
#include <stdexcept>
void call_python_method(PyObject* self, const char* method)
{
// check arguments
if ( 0 == self || 0 == method ) { throw std::runtime_error("Invalid Python object and method"); }
// call Python
PyObject* r = PyObject_CallMethod(self, const_cast<char*>(method), const_cast<char*>(""));
if ( 0 == r ) { PyErr_Print(); return;}
// release used objects
Py_XDECREF( r ) ;
//
return;
}
class Base {
public:
Base() {}
virtual ~Base() {}
virtual void Foo() { cout << "base::Foo" << endl; }
void CallFoo() { this->Foo(); }
};
class PyBase : public Base {
public:
PyBase(PyObject* self) : fSelf(self) {}
virtual ~PyBase() {}
virtual void Foo() { call_python_method(fSelf,"Foo"); }
private:
PyObject* fSelf;
};
Out[2]:
Now we define the python PyDerived class that inherits from the just declared C++ PyBase
In [3]:
class PyDerived(ROOT.PyBase):
def __init__(self): ROOT.PyBase.__init__(self, self)
def Foo(self): print 'Python::Foo'
Now that we have the two classes defined (Base and PyDerived) we exercise calling the Foo method.
In [4]:
o = ROOT.Base()
o.CallFoo()
d = PyDerived()
d.CallFoo()
If we put the objects in a std::vector<Base*> we can exercise true polymorphic access from the C++ side
In [5]:
v = ROOT.vector('Base*')()
v.push_back(o)
v.push_back(d)
for i in v : i.Foo()
Notice that the printout order is not correct (there is a bug in the current ROOTaaS implementation) becuase the Python output somehow overtakes the C++ generated output.