enchancements inherit_CPP_classes - cython/cython GitHub Wiki

CEP 529: Allow Python Extension Types to Auto Inherit from C++ Classes

  • Status: Open
  • Implementation status: Not started

Motivation

Provide support for interfacing with C++ polymorphic frameworks, note this can be done manually by writing a C++ Interface class, however with a small amount of extra information (i.e. if a method is virtual, pure virtual, or not virtual) on C++ class Definition, Cython can autogenerate this interface class and a base extension type that links with the interface class.

Concept

Consider the following C++ Class

class Base {
    public:
        Base();
        ~Base();
        virtual int pvmethod(int a); // pure virtual
        virtual int vmethod(int a) { return a; } // virtual method
        int method(int a) { return 2*a+1; } // Normal method
}

and Cython Definition

cdef extern from ...:
    cdef cppclass Base:
        Base()
        pure virtual int pvmethod(int a)
        virtual int vmethod(int a)
        int method(int a)

we could declare a Extension type as

cdef class PyBase(Base):
    pass

Code would be generate along the lines of cpdef functions as follows:

C++ Python aware wrapper class

class pyxBase: Base {
    PyObject *py_obj
    public:
        pyxBase(PyObject *obj): py_obj(obj);
        ~pyxBase(PyObject *obj);
        virtual int pvmethod(int a) { return PyBase_pvmethod(py_obj, a); }
        virtual int vmethod(int a) { return PyBase_vmethod(py_obj, a); }
}

and a effective Cython Extenstion type of

cdef class PyBase:
     cdef pyxBase* c_ptr
     def __cinit__(self):
         self.c_ptr = new pyxBase(self)
     def __dealloc__(self):
         if self.c_ptr:
             del self.c_ptr
     cpdef int pvmethod(PyBase self, int a): # Exposed to c as int PyBase_pvmethod(PyBase *, int)
         raise Error("Can't Call Pure Virtual Method 'pvmethod' of C++ class 'Base'")
     cpdef int vmethod(PyBase self, int a): # Exposed to c as int PyBase_vmethod(PyBase *, int)
         return self.c_ptr.Base.vmethod(a)
     cpdef int method(PyBase self, int a): # Exposed to c as int PyBase_method(PyBase *, int)
         return self.c_ptr.method(a)

since cpdef, functions already check if their redefined by python, at c level, this will either call the python redefinition, or attempt to call the method on the base class

self.c_ptr.Base.vmethod(a)

is consider to be represented by the following C code

_p_self.c_ptr.Base::vmethod(a) // _p_self is the point to PyBase, with is the extension type strut

This explicitly calls the Base method not the overload

Then if PyBase is passed to a C++ function expecting Base *, Cyhton would actually pass PyBase.c_ptr, which would be a pointer to a pyxBase Object.

This can be auto-generated as the only dependency is the virtualness of the functions on the base C++ class.