Cython 指针继承

Cython Pointer Inheritance

问题

我有一个基础 class LinkPredictor 和一个从 C++ 中的 LinkPredictor 派生的子 class KatzIndex。 现在我有另一个 class,它的构造函数中需要一个指向 LinkPredictor.

的指针

我想将那些 class 包装在 Cython 中,以便在 Python 中可用。

我的尝试

菲律宾共产党:

class LinkPredictor { ... }
class KatzIndex : public LinkPredictor { ... }
class KFoldCrossValidator {
public:
  KFoldCrossValidator(LinkPredictor* lp) { ... }
}

赛通:

cdef extern from ".../LinkPredictor.h":
    cdef cppclass _LinkPredictor:
        _LinkPredictor(...) except +

cdef class LinkPredictor:
    def __cinit__(self):
        return

cdef extern from ".../KatzIndex.h":
    cdef cppclass _KatzIndex(_LinkPredictor):
        _KatzIndex(...) except +
        ...

cdef class KatzIndex(LinkPredictor):
    cdef _KatzIndex* _this
    ...

cdef extern from ".../KFoldCrossValidator.h":
    cdef cppclass _KFoldCrossValidator:
        _KFoldCrossValidator(_LinkPredictor* linkPredictor) except +
        ...

cdef class KFoldCrossValidator:
    cdef _KFoldCrossValidator* _this

    def __cinit__(LinkPredictor linkPredictor):
        self._this = new _KFoldCrossValidator(linkPredictor._this)
    ...

问题

上述方法无效。 Cython 抛出以下错误消息:

Error compiling Cython file:
------------------------------------------------------------
...
    cdef _KFoldCrossValidator* _this

    def __cinit__(self, LinkPredictor linkPredictor):
        self._this = new _KFoldCrossValidator(linkPredictor._this)
                                              ^
------------------------------------------------------------

.../project.pyx:X:Y: Cannot convert Python object to '_LinkPredictor *'

我认为发生这种情况是因为 _this 仅在 KatzIndex 中声明,它具有类型 _KatzIndex* 而不是 _LinkPredictor*。现在我尝试声明 _LinkPredictor_KatzIndex 的继承关系(通过声明 _KatzIndex(_LinkPredictor)),并希望 Cython 接受类型为 _LinkPredictor*_this 作为 _KatzIndex 派生自 _LinkPredictor。但好像不是这样。

你对此有何看法?

你的问题是你的 python 基础 class (LinkPredictor) 的包装器需要包含一个指针成员,然后它可以被派生的 classes 覆盖。

举个例子,我们正在包装以下 C++ 库:

foo.hpp

class Base {
public:
    virtual double a();
};

class Derived : public Base {
public:
    virtual double a();
};

class Using {
public:
    double a;
    Using(Base *b);
};

foo.cpp

#include "foo.hpp"

double Base::a()
{
    return 1.0;
}

double Derived::a()
{
    return 2.0;
}

Using::Using(Base *b) : a(b->a())
{}

然后我们可以将包装器写成

pyfoo.pyx

cdef extern from "foo.hpp":
    cdef cppclass Base:
        Base() except +

    cdef cppclass Derived(Base):
        Derived() except +

    cdef cppclass Using:
        Using(Base *b) except +
        double a

cdef class PyBase(object):
    cdef Base *_this
    def __cinit__(self):
        if type(self) != PyBase:
            return
        self._this = new Base()

    def __dealloc__(self):
        if self._this is not NULL:
            del self._this
            self._this = NULL

cdef class PyDerived(PyBase):
    def __cinit__(self):
        self._this = new Derived()

    def __dealloc__(self):
        if self._this is not NULL:
            del self._this
            self._this = NULL

cdef class PyUsing(object):
    cdef Using *_this
    def __cinit__(self, PyBase b):
        self._this = new Using(b._this)

    def a(self):
        return self._this.a

    def __dealloc__(self):
        if self._this is not NULL:
            del self._this
            self._this = NULL

除此之外,您可能还想通读这篇 tutorial