Как избежать переопределения базового класса при использовании Cython для предоставления классов C ++ с наследованием Python

Я пытаюсь использовать библиотеку, написанную на c ++ из Python. Библиотека состоит из нескольких классов, унаследованных от базового класса, каждый класс имеет свои собственные файлы .cpp и .h.

При использовании Cython для получения доступа к этим классам (мне нужны только дочерние классы, но с методами из базового класса) я могу заставить его работать, только переопределив базовый класс в файлах pxd и pyx для всех дочерних классов.

Если я попытаюсь определить файл pxd (и pyx) для базового класса, я столкнусь с проблемами, связанными с тем, что заголовок для моего базового класса будет несколько раз включен в файл .cpp, созданный Cython, что приведет к ошибке: переопределение класса BaseClass '

Каков правильный макет проекта для такой установки?

Я работаю над Ubuntu 16.04LTS, Python 3.5.2, Cython 0.29.7

Поскольку MWE уже включает в себя довольно много файлов, я показываю здесь только несколько фрагментов, но полный код находится на GitHub: https://github.com/Heerpa/test_cython_cpp/commit/master

В MWE у меня есть базовый класс Mammal и два дочерних класса Cat и Dog. Дочерние классы используют метод run () из класса Mammal, но определяют свои собственные методы eat ().

В макете, который будет мне понятен, есть файлы для базового класса:

# c_mammal.pxd

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

и определение дочерних классов, например Кот:

# 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()

а также определите функциональность Mammal в 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()

И дело в том, что я должен написать точно такой же код Mammal и в файлах собачьего cython. Это работает, но не может быть предполагаемым решением.


person Heinrich    schedule 03.05.2019    source источник
comment
Есть ли в вашем файле mamal.h охранники? Должно.   -  person Martin Bonner supports Monica    schedule 03.05.2019
comment
Я посмотрел репозиторий git. Нет, это не так. (Кроме того, вы не должны включать iostream в mammal.h - вам не нужно какое-либо определение из iostream для определения класса млекопитающих.   -  person Martin Bonner supports Monica    schedule 03.05.2019
comment
Отлично, спасибо! Может быть, мне следовало добавить, что мои дни C ++ были короткими и давними. Защитники включения заставляют его работать (en.wikipedia.org/wiki/Include_guard). Я действительно использую std :: cout в mammal.cpp, и я подумал, что вспомнил, что все, что включает в себя .cpp, входит в его заголовок !? Могу ли я чему-то еще научиться?   -  person Heinrich    schedule 04.05.2019