cdef function can be only overriden by a cdef (or cpdef) function in the derived class. This is also the reason, cython emits warning:
warning: xxxxx.pyx:yy:z: Overriding cdef method with def method.
for the example above.
The usual def-function is very flexible: Not only multiple inheritances must be taken into account, but for example also monkey-patching. But that also means there is not much place for optimization: there is not much more Cython can do than using python's machinery, i.e. PyObject_GetAttr/PyObject_GenericGetAttr + PyMethod_GET_SELF + PyMethod_GET_FUNCTION+ call of the function.
This flexibility leads to large overhead, so cdef-functions avoid it by using a different strategy, which is similar to C++-virtual functions:
- Every
cdef-class has a virtual table, where the pointer to cdef-functions are stored, every one in its own slot.
- Every object of this
cdef-class has a pointer to this virtual table thus the calls to cdef-functions can be resolved at the run time and the resolution costs only an indirection.
- A subclass can override a
cdef-function by putting another function-pointer into the correspoding slot in the virtual table.
A typicall call of the cdef-function looks as follows:
%%cython
cdef class A:
cdef doit(self):
print(42)
def call_doit(self):
self.doit()
The self.doit() leads to the following c-code:
((struct __pyx_vtabstruct_XXX_A*)__pyx_v_self->__pyx_vtab)->doit(__pyx_v_self, 0);
The v-table of the object __pyx_v_self is interpreted as v-table of the cdef-class A (even if self is not an instance of A but of a derived class, this operation works correctly) and slot doit is executed.
When a class, let's say B derives from A it can override the slot doit, so B's version of the doit were called. The slot doit is overriden by providing a corresponding definition of cdef-function.
As one can see, there are different machineries at play when a def function is called compared to a cdef-function.
Thus cdef functions are overriden only by other cdef-functions (and not def-functions). Being more precise, one can also use a cpdef-method for overwriting - but in your example it will not work because cpdef functions cannot have double * arguments, as they cannot be converted automatically by Cython to Python-objects,and the signatures of the overriding and overrided functions must match.