I am using Cython to wrap a set of C++ classes, allowing a Python interface to them. Example Code is provided below:
BaseClass.h:
#ifndef __BaseClass__
#define __BaseClass__
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
class BaseClass
{
public:
BaseClass(){};
virtual ~BaseClass(){};
virtual void SetName(string name){printf("in base set name\n");}
virtual float Evaluate(float time){printf("in base Evaluate\n");return 0;}
virtual bool DataExists(){printf("in base data exists\n");return false;}
};
#endif /* defined(__BaseClass__) */
DerivedClass.h:
#ifndef __DerivedClass__
#define __DerivedClass__
#include "BaseClass.h"
class DerivedClass:public BaseClass
{
public:
DerivedClass(){};
virtual ~DerivedClass(){};
virtual float Evaluate(float time){printf("in derived Evaluate\n");return 1;}
virtual bool DataExists(){printf("in derived data exists\n");return true;}
virtual void MyFunction(){printf("in my function\n");}
virtual void SetObject(BaseClass *input){printf("in set object\n");}
};
#endif /* defined(__DerivedClass__) */
NextDerivedClass.h:
#ifndef __NextDerivedClass__
#define __NextDerivedClass__
#include "DerivedClass.h"
class NextDerivedClass:public DerivedClass
{
public:
NextDerivedClass(){};
virtual ~NextDerivedClass(){};
virtual void SetObject(BaseClass *input){printf("in set object of next derived class\n");}
};
#endif /* defined(__NextDerivedClass__) */
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()
void SetObject(BaseClass *)
cdef extern from "NextDerivedClass.h":
cdef cppclass NextDerivedClass(DerivedClass):
NextDerivedClass() except +
# *** The issue is right here ***
void SetObject(BaseClass *)
cdef class PyBaseClass:
cdef BaseClass *thisptr
def __cinit__(self):
if type(self) is PyBaseClass:
self.thisptr = new BaseClass()
def __dealloc__(self):
if type(self) is PyBaseClass:
del self.thisptr
cdef class PyDerivedClass(PyBaseClass):
cdef DerivedClass *derivedptr
def __cinit__(self):
self.derivedptr = self.thisptr = new DerivedClass()
def __dealloc__(self):
del self.derivedptr
# def Evaluate(self, time):
# return self.derivedptr.Evaluate(time)
def SetObject(self, PyBaseClass inputObject):
self.derivedptr.SetObject(<BaseClass *>inputObject.thisptr)
cdef class PyNextDerivedClass(PyDerivedClass):
cdef NextDerivedClass *nextDerivedptr
def __cinit__(self):
self.nextDerivedptr = self.thisptr = new NextDerivedClass()
def __dealloc__(self):
del self.nextDerivedptr
def SetObject(self, PyBaseClass input):
self.nextDerivedptr.SetObject(<BaseClass *>input.thisptr)
I want to be able to call SetObject in Python similar to as shown below:
main.py:
from inheritTest import PyBaseClass as base
from inheritTest import PyDerivedClass as der
from inheritTest import PyNextDerivedClass as nextDer
#This works now!
a = der()
b = der()
a.SetObject(b)
#This doesn't work -- keeping the function declaration causes a overloaded error, not keeping it means the call below works, but it calls the inherited implementation (From derived class)
c = nextDer()
c.SetObject(b)
I thought it would work since the classes inherit from each other, but its giving me the following error:
Argument has incorrect type: expected PyBaseClass, got PyDerivedClass
Not specifying type in the function definition makes it think that the inputObject is a pure Python object (has no C-based attributes, which it does), in which case the error is:
*Cannot convert Python object to BaseClass *
A sort-of hacky workaround to this just to have Python functions with different names that expect different types of arguments (ex: SetObjectWithBase, SetObjectWithDerived), and then within their implementation, just call the same C-based function having type-casted the input. I know for a fact this works, but I would like to avoid having to do this as much as possible. Even if there is a way I can catch the Type Error within the function, and deal with it inside, I think that might work, but I wasn't sure exactly how to implement that.
Hope this question makes sense, let me know if you require additional information.
****EDIT****: Code has been edited such that basic inheritance works. After playing around with it a bit more, I realize that the problem is occurring for multiple levels of inheritance, for example, see edited code above. Basically, keeping the declaration for SetObject for the NextDerivedClass causes a "Ambiguous Overloaded Method" error, not keeping it allows me to call the function on the object, but it calls the inherited implementation (from DerivedClass). **