我使用Cython来包装一组C++类,允许Python接口。示例代码如下:
基类.h:
#ifndef __BaseClass__
#define __BaseClass__
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
class BaseClass
{
public:
BaseClass(){};
virtual ~BaseClass(){};
virtual void SetName(string name){printf("in base set name\n");}
virtual float Evaluate(float time){printf("in base Evaluate\n");return 0;}
virtual bool DataExists(){printf("in base data exists\n");return false;}
};
#endif /* defined(__BaseClass__) */
DerivedClass.h:
^{pr2}$下一节课:
#ifndef __NextDerivedClass__
#define __NextDerivedClass__
#include "DerivedClass.h"
class NextDerivedClass:public DerivedClass
{
public:
NextDerivedClass(){};
virtual ~NextDerivedClass(){};
virtual void SetObject(BaseClass *input){printf("in set object of next derived class\n");}
};
#endif /* defined(__NextDerivedClass__) */
在继承测试.pyx公司名称:
cdef extern from "BaseClass.h":
cdef cppclass BaseClass:
BaseClass() except +
void SetName(string)
float Evaluate(float)
bool DataExists()
cdef extern from "DerivedClass.h":
cdef cppclass DerivedClass(BaseClass):
DerivedClass() except +
void MyFunction()
float Evaluate(float)
bool DataExists()
void SetObject(BaseClass *)
cdef extern from "NextDerivedClass.h":
cdef cppclass NextDerivedClass(DerivedClass):
NextDerivedClass() except +
# *** The issue is right here ***
void SetObject(BaseClass *)
cdef class PyBaseClass:
cdef BaseClass *thisptr
def __cinit__(self):
if type(self) is PyBaseClass:
self.thisptr = new BaseClass()
def __dealloc__(self):
if type(self) is PyBaseClass:
del self.thisptr
cdef class PyDerivedClass(PyBaseClass):
cdef DerivedClass *derivedptr
def __cinit__(self):
self.derivedptr = self.thisptr = new DerivedClass()
def __dealloc__(self):
del self.derivedptr
# def Evaluate(self, time):
# return self.derivedptr.Evaluate(time)
def SetObject(self, PyBaseClass inputObject):
self.derivedptr.SetObject(<BaseClass *>inputObject.thisptr)
cdef class PyNextDerivedClass(PyDerivedClass):
cdef NextDerivedClass *nextDerivedptr
def __cinit__(self):
self.nextDerivedptr = self.thisptr = new NextDerivedClass()
def __dealloc__(self):
del self.nextDerivedptr
def SetObject(self, PyBaseClass input):
self.nextDerivedptr.SetObject(<BaseClass *>input.thisptr)
我希望能够在Python中调用SetObject,如下所示:
在主.py公司名称:
from inheritTest import PyBaseClass as base
from inheritTest import PyDerivedClass as der
from inheritTest import PyNextDerivedClass as nextDer
#This works now!
a = der()
b = der()
a.SetObject(b)
#This doesn't work -- keeping the function declaration causes a overloaded error, not keeping it means the call below works, but it calls the inherited implementation (From derived class)
c = nextDer()
c.SetObject(b)
我原以为这是可行的,因为这些类是相互继承的,但它给了我以下错误:
参数的类型不正确:应为PyBaseClass,而get为PyDerivedClass
在函数定义中不指定类型会使它认为inputObject是纯Python对象(它没有基于C的属性,但它没有),在这种情况下,错误是:
*无法将Python对象转换为基类*
一种解决这一问题的方法就是使用不同名称的Python函数来期望不同类型的参数(例如:SetObjectWithBase、SetObjectWithDerived),然后在它们的实现中,只需调用相同的基于C的函数,并将类型转换为输入。我知道这是可行的,但我想尽量避免这样做。即使有一种方法可以捕捉函数中的类型错误,并在函数内部处理它,我认为这可能有效,但我不确定如何实现它。在
希望这个问题有意义,如果你需要更多的信息请告诉我。在
****编辑*****:已对代码进行了编辑,以便基本继承可以工作。在对它进行了更多的研究之后,我意识到问题发生在多个继承级别上,例如,请参阅上面编辑的代码。基本上,为NextDerivedClass保留SetObject声明会导致一个“不明确的重载方法”错误,不保留它允许我调用对象上的函数,但它调用继承的实现(从deriveClass)。**在
经过以下答案的大量帮助和实验,我想我理解了在Cython中实现基本继承是如何工作的,我正在回答我自己的问题,以验证/改进我的理解,并希望能帮助任何将来可能遇到相关问题的人。如果这个解释有任何错误,请在下面的评论中纠正我,我会编辑它。我不认为这是唯一的方法,所以我确信其他方法也能起作用,但这是对我有效的方法。在
概述/学到的东西:
基本上,根据我的理解,Cython足够聪明(给出适当的信息)遍历继承层次结构/树,并根据调用它的对象类型调用虚拟函数的适当实现。在
<>重要的是尝试镜像你在.pYX文件中试图包装的C++继承结构。这意味着确保:1)导入的C++/Cython cppclasses(声明为^ {CD1>})与实际C++类做
的方式继承2)对于每个导入的类,只声明唯一的方法/成员变量(对于在两个类中实现不同的虚拟函数,}不应同时具有函数声明)。只要一个从另一个继承,函数声明只需要在基类imported中。在
BaseClass
和{3)Python包装类(即{{CD4>}/^ {CD5>})也应该以与实际C++类做
相同的方式彼此继承。4)与上述类似,虚函数的接口只需存在于
PyBase
包装类中(不应同时放入这两个类中,实际运行代码时将调用正确的实现)。在5)对于每个Python包装类的子类或继承类,您需要在
__cinit__()
和__dealloc__()
函数中同时进行if type(self) is class-name:
检查。这将防止seg错误等。您不需要检查层次树中的“叶节点”(不会继承或子类化的类)6)确保在
__dealloc__()
函数中,只删除当前指针(而不是任何继承的指针)7)同样,在
__cinit__()
中,对于继承的类,请确保您设置了当前指针,以及指向您试图创建的类型的对象的所有派生指针(即*self.nextDerivedptr = self.derivedptr = self.thisptr = new NextDerivedClass()*
)希望上面的几点在您看到下面的代码时有很大的意义,它编译并运行/按照我的需要/希望它工作。在
基类.h:
DerivedClass.h:
^{pr2}$NextDerivedClass.h:
在继承测试.pyx公司名称:
在测试.py公司名称:
请注意,当我打电话给:
它的工作方式是Cython沿着继承树寻找 “最新”实施评估。如果它存在于
NextDerivedClass.h
中,它会调用它(我已经尝试过了,它起作用了),但是由于它不在那里,它会更进一步并检查DerivedClass
。该功能在那里实现,因此输出为:我希望这对将来的人有所帮助,同样,如果我的理解有错误,或者只是语法/语法方面的错误,请随时在下面发表评论,我会尽力解决它们。再次感谢下面的回答者,这是他们答案的总结,只是为了帮助验证我的理解。谢谢!在
编写的代码无法编译。我怀疑你的实数
PyDerivedClass
并不是真的从PyBaseClass
派生出来的,就像它真的那样这也可以解释你得到的类型错误,这是一个我无法重现的错误。在
老实说,这看起来像个虫子。传入的对象是所需类的一个实例,但它仍然抛出一个错误。你可以把它放在cython用户的邮件列表中,这样主要的开发人员就可以看到它了。在
一种可能的解决方法是定义一个表示两种类型参数的fused type,并在方法中使用它。不过,这似乎有点过分了。在
相关问题 更多 >
编程相关推荐