I need to embed my Cython classes in some C++ code, and I cannot get the inheritance to work, and keep getting segmentation faults when trying to access fields of the base class. Due to the constraints of the project, it is not possible to wrap the C++ class or remove the classes from the Cython code. Here is a distilled example of my problem:
<<< file: fooClass.pyx >>>
from math import sin
cdef public class FooSuper[object FooSuper, type FooSuperType]:
def __init__ (self, a):
print "FooSuper.__init__ START"
self.a = a
print "FooSuper.__init__ END"
cdef public class Foo[object Foo, type FooType]:
def __init (self, a, b):
print "Foo.__init__ START"
FooSuper.__init__(self, a)
self.b = b
print "Foo.__init__ END"
cdef double bar (self, double c):
return sin(self.a * c)
cdef public Foo buildFoo (double a, double b):
print "buildFoo(a,b) START"
return Foo(a,b)
cdef public double foobar (Foo foo, double c):
print "foobar(Foo,c) START"
return foo.bar(d)<<< file: foo.cc >>>
#include <Python.h>
#include "fooClass.h"
#include <iostream>
int main(){
Py_Initialize();
initfooClass();
Foo *foo = buildFoo(1.0, 2.0);
std::cout << foobar(foo, 3.0) << std::endl;
Py_Finalize()
}When I run this, I receive the following:
<<< std out >>>
buildFoo(a,b)
Foo.__init__ START
foobar(Foo,d)
Segmentation faultI know that this approach to embedding Cython in C++ works with just the Foo class, but when I try to extend Foo from FooSuper, the FooSuper.__init__ is never called. I know this problem must come from my method of initializing, but I have converted both __init__s to __cinit__s with no change. Clearly the segfault is coming from the fields of FooSuper not being initialized at all. I have also tried adding a hollow __cinit__(self, *args) to the FooSuper class with no change. If anyone can help me out, I'd be very appreciative. Thanks.
So after some more attempts I have managed to answer my own question. The problem was in, as I suspected, the initialization of the super class. Here is the result:
<<< fooClass.pyx >>>
from math import sin
cdef public class FooSuper[object FooSuper, type FooSuperType]:
cdef double a
#This is needed to initialize the underlying C struct of the super class
cdef __cinit__(self, *argv):
print "FooSuper.__cinit___()"
def __init__(self, a):
print "FooSuper.__init__() START"
self.a = a
print "FooSuper.__init__() END"
cdef public class Foo(FooSuper) [object Foo, type FooType]:
cdef double b
def __init__(self, a, b):
print "Foo.__init__() START"
FooSuper.__init__(self, a)
print "Foo.__init__() END"
cdef double bar (self, double c):
return sin(self.a*c)
cdef public Foo buildFoo (double a, double b):
print "buildFoo(a,b)"return Foo(a,b)
cdef public double foobar(Foo foo, double c):
print "foobar(Foo, c)"
return foo.foobar(c)<<< foo.cc >>>
#include <Python.h>
#include "fooClass.h"
#include <iostream>
int main(){
Py_Initialize();
initfooClass();
Foo *foo = buildFoo(1.0, 2.0);
std::cout << foobar(foo, 3.0) << std::endl;
Py_Finalize()
}This compiles and runs without problem.