用于声明具有别名的类层次结构的Cython语法

Cython syntax for declaring class hierarchies that have aliases

本文关键字:层次结构 Cython 语法 别名 声明 用于      更新时间:2023-10-16

这里有一个抽象基类和一个具体子类,我想通过Cython:将其公开给Python

class NodeDistance {
protected:
    const Graph& G;
public:
    NodeDistance(const Graph& G);
    virtual ~NodeDistance();
    virtual void preprocess() = 0;
    virtual double distance(node u, node v) = 0;
};

class NeighborhoodDistance: public NetworKit::NodeDistance {
public:
    NeighborhoodDistance(const Graph& G);
    virtual ~NeighborhoodDistance();
    virtual void preprocess();
    virtual double distance(node u, node v);
};

这是我第一次尝试为Cython声明类的接口。为了避免cppclasses和Python包装类之间的命名冲突,我将每个Class声明为_Class,然后声明其正确名称"Namespace::Class"

cdef extern from "../cpp/distmeasures/NodeDistance.h":
    cdef cppclass _NodeDistance "NetworKit::NodeDistance":
        _NodeDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +

cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
        _NeighborhoodDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +

但现在我在试图表达_NeighborhoodDistance_NodeDistance的子类时遇到了语法错误。我做错了什么?

Error compiling Cython file:
------------------------------------------------------------
...
        void preprocess() except +
        double distance(node, node) except +

cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
                                                   ^
------------------------------------------------------------
_NetworKit.pyx:1698:52: Syntax error in C++ class definition

我认为您甚至无法在Cython 0.20.1中表达基类和重命名的组合。您可以不重命名类,而是在cdef extern from:中指定名称空间

# C++ classes shown at the end
cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base:
        void some_method() except +
    cdef cppclass Derived(Base):
        void some_method() except +

或不指定继承:

cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base "example::Base":
        void some_method() except +
    cdef cppclass Derived "example::Derived":
        void some_method() except +

不管怎样,Cython似乎并没有完全理解C++继承,您需要一个显式的强制转换:

def test():
    cdef Derived d
    cdef Base *p = <Base *>&d
    p.some_method()

这很难看,因为在C++中,强制转换有效地关闭了类型检查,但要小心,它可以安全地使用。(在其他情况下,Cython的类型检查需要C/C++中不需要的类型转换,这是非常不幸的。(

作为参考,以下是我使用的类:

// example.hpp
#include <cstdio>
namespace example {
    struct Base {
        virtual void some_method() = 0;
        virtual ~Base() = 0;
    };
    struct Derived {
        virtual void some_method()
        {
            std::puts("Hello!");
        }
        ~Derived()
        {
        }
    };
}