Reputation: 593
Using Cython (acting as an interface so I can call C++ based functions via Python), I am trying to wrap a complicated hierarchal structure of C++ classes, all of which eventually inherit from one base class. This singular base class has many virtual functions, whose implementation is different based on the derived class under consideration. Derived classes also have their own unique functions as well.
I am having a lot of trouble wrapping this via Cython, primarily because I can't find a way to re-define self.thisptr within each of the inherited classes to be of that specific type (rather than the type of the singular base class). I have also tried type-casting, as well as trying to delete the pointer and then re-initialize it, but it still thinks its pointing to the same base class. Example code is below:
inheritTest.pyx:
cdef extern from "BaseClass.h":
cdef cppclass BaseClass:
BaseClass() except +
void SetName(string)
float Evaluate(float)
bool DataExists()
cdef extern from "DerivedClass.h":
cdef cppclass DerivedClass(BaseClass):
DerivedClass() except +
void MyFunction()
float Evaluate(float)
bool DataExists()
SetObject(BaseClass *)
cdef class PyBaseClass:
cdef BaseClass *thisptr
def __cinit__(self):
self.thisptr = new BaseClass()
def __dealloc__(self):
del self.thisptr
cdef class PyDerivedClass(PyBaseClass):
#This is one of the solutions that I have tried
def __cinit__(self):
if(self.thisptr):
del self.thisptr
self.thisptr = new DerivedClass()
def __dealloc__(self):
del self.thisptr
def Evaluate(self, time):
#I need to call the Derived implementation of this function, not Base
return self.thisptr.Evaluate(self,time)
def SetObject(self, PyBaseClass inputObject):
#The issue here is that it looks for SetObject to be declared in BaseClass and spits an error otherwise. If I put a empty declaration, the complain is of ambiguous method overload
self.thisptr.SetObject(inputObject.thisptr)
Also, when I call SetObject in my Python script, I want to be able to pass in a PyDerived Object as input, since it inherits from PyBase, shouldn't it just work? I tried it and the error is that:
Argument has incorrect type: expected PyBase, got PyDerived
Hopefully my questions make sense, please let me know if you require any additional information :)
Upvotes: 2
Views: 441
Reputation: 10700
Rather than deleting the old copies of self.thisptr
, just make the constructor for the base class only initialize the pointer if the type of self
is the base class.
def __cinit__(self):
if type(self) is PyBaseClass:
self.thisptr = new BaseClass()
Be sure you guard against deallocation the same way in the base class __dealloc__
method as well.
Then, to avoid a bunch of unnecessary casts, in the subclass wrapper, make two different attributes, one storing the pointer to the c++ object cast to the type of the base class and the other storing the pointer to the c++ object with its original type. Something like this:
cdef DerivedClass* derivedptr
def __cinit__(self):
self.derivedptr = self.thisptr = new DerivedClass()
Then, when you need to access the methods of the derived class, use the derived pointer instead.
Be sure that, when deallocating, you only delete the derived pointer.
I got this idea from this discussion on the Cython Users mailing list.
Upvotes: 1