首页 > 解决方案 > 使用 Cython 向 Python 公开具有继承的 C++ 类时如何避免基类重新定义

问题描述

我正在尝试使用 Python 中用 c++ 编写的库。该库由从基类继承的多个类组成,每个类都有自己的 .cpp 和 .h 文件。

当使用 Cython 访问这些类时(我只需要子类,但使用基类中的方法),我只能通过在 pxd 和 pyx 文件中为所有子类重新定义基类来使其工作。

如果我尝试为基类定义一个 pxd(和 pyx)文件,我会遇到问题,即我的基类的标头多次包含在 Cython 创建的 .cpp 文件中,引发错误:重新定义'class BaseClass '

这种设置的正确项目布局是什么?

我正在开发 Ubuntu 16.04LTS、Python 3.5.2、Cython 0.29.7

由于 MWE 已经涉及不少文件,我这里只展示几个片段,但完整代码在 GitHub 上: https ://github.com/Heerpa/test_cython_cpp/commits/master

在 MWE 中,我有一个基类 Mammal,以及两个子类 Cat 和 Dog。子类使用 Mammal 类的 run() 方法,但定义了自己的 eat() 方法。

对我来说有意义的布局确实有基类的文件:

# c_mammal.pxd

def extern from 'CMammal.h':
    cdef cppclass CMammal:
        void run()

以及子类的定义,例如 Cat:

# c_cat.pxd
from c_mammal cimport CMammal


cdef extern from 'CCat.h':
    # cdef cppclass CMammal:
    #     void run()
    cdef cppclass CCat(CMammal):
        void eat()

现在,由于 CCat.h 包含 CMammal.h 以便从中继承,我得到重新定义错误

building 'animals.dog' extension
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Isrc/animalcpplibrary/ -I/usr/include/python3.5m -c src/dog.cpp -o build/temp.linux-x86_64-3.5/src/dog.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
In file included from src/animalcpplibrary/CDog.h:2:0,
                 from src/dog.cpp:623:
src/animalcpplibrary/CMammal.h:3:7: error: redefinition of ‘class CMammal’
 class CMammal {
       ^
In file included from src/dog.cpp:622:0:
src/animalcpplibrary/CMammal.h:3:7: error: previous definition of ‘class CMammal’
 class CMammal {
       ^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

相反,如果我使用 CMammal 包含在 CCat 中的事实,我可以这样做:

# c_cat.pxd
cdef extern from 'CCat.h':
    cdef cppclass CMammal:
        void run()
    cdef cppclass CCat(CMammal):
        void eat()

并在 cat.pyx 中定义哺乳动物的功能:

# cat.pyx

# distutils: sources = [src/animalcpplibrary/CCat.cpp, src/animalcpplibrary/CMammal.cpp]
# distutils: language = c++
# distutils: include_dirs = src/animalcpplibrary/
# cython: language_level=3

cimport c_cat

cdef class PyMammal:
    cdef c_cat.CMammal* thisptr

    def run(self):
        if self.thisptr:
            self.thisptr.run()


cdef class PyCat(PyMammal):
    def __cinit__(self):
        if self.thisptr:
            del self.thisptr
        print('cinit Cat: allocating instance.')
        self.thisptr = new c_cat.CCat()

    def __dealloc__(self):
        if self.thisptr:
            print('dealloc Cat: deallocating instance')
            del self.thisptr

    def eat(self):
        if self.thisptr:
            (<c_cat.CCat*>self.thisptr).eat()

而且,关键是,我还必须在狗 cython 文件中编写完全相同的哺乳动物代码。这可行,但不能成为预期的解决方案。

标签: pythonc++inheritancecythonproject-layout

解决方案


推荐阅读