Cython指针继承

时间:2015-03-19 23:15:58

标签: cython

问题

我有一个基类LinkPredictor和一个子类KatzIndex,它源自LinkPredictor中的C++。 现在我有另一个类,它在构造函数中需要一个指向LinkPredictor的指针。

我希望将这些类包装在Cython中,以便在Python中使用它们。

我的尝试

CPP:

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

用Cython:

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接受类型为_this的{​​{1}}为{ {1}}来自_LinkPredictor*。但事实似乎并非如此。

您对此有何看法?

1 个答案:

答案 0 :(得分:2)

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

举个例子说我们正在包装以下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