【问题标题】:Multiple Inheritance/Virtual Functions多重继承/虚函数
【发布时间】:2015-02-17 22:03:37
【问题描述】:

使用 Cython(充当接口,因此我可以通过 Python 调用基于 C++ 的函数),我试图包装 C++ 类的复杂层次结构,所有这些最终都继承自一个基类。这个单一的基类有许多虚函数,它们的实现根据所考虑的派生类而有所不同。派生类也有自己独特的功能。

我在通过 Cython 包装它时遇到了很多麻烦,主要是因为我找不到在每个继承的类中将 self.thisptr 重新定义为该特定类型的方法(而不是单数基类的类型)。我也尝试过类型转换,以及尝试删除指针然后重新初始化它,但它仍然认为它指向同一个基类。示例代码如下:

inheritTest.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()
        SetObject(BaseClass *)

cdef class PyBaseClass:
    cdef BaseClass *thisptr
    def __cinit__(self):
        self.thisptr = new BaseClass()
    def __dealloc__(self):
        del self.thisptr

cdef class PyDerivedClass(PyBaseClass):
    #This is one of the solutions that I have tried
    def __cinit__(self):
        if(self.thisptr):
            del self.thisptr
        self.thisptr = new DerivedClass()
    def __dealloc__(self):
        del self.thisptr
    def Evaluate(self, time):
        #I need to call the Derived implementation of this function, not Base
        return self.thisptr.Evaluate(self,time)
    def SetObject(self, PyBaseClass inputObject):
         #The issue here is that it looks for SetObject to be declared in BaseClass and spits an error otherwise. If I put a empty declaration, the complain is of ambiguous method overload
         self.thisptr.SetObject(inputObject.thisptr)

另外,当我在我的 Python 脚本中调用 SetObject 时,我希望能够传入一个 PyDerived 对象作为输入,因为它继承自 PyBase,它不应该正常工作吗?我试过了,错误是:

参数类型不正确:预期 PyBase,得到 PyDerived

希望我的问题有意义,如果您需要任何其他信息,请告诉我:)

【问题讨论】:

    标签: python c++ inheritance virtual cython


    【解决方案1】:

    与其删除self.thisptr的旧副本,不如让基类的构造函数只在self的类型是基类时才初始化指针。

    def __cinit__(self):
        if type(self) is PyBaseClass:
            self.thisptr = new BaseClass()
    

    确保在基类__dealloc__ 方法中也以同样的方式防止释放。

    然后,为了避免一堆不必要的转换,在子类包装器中,制作两个不同的属性,一个存储指向 c++ 对象的指针强制转换为基类的类型,另一个存储指向 c++ 对象的指针它的原始类型。像这样的:

    cdef DerivedClass* derivedptr
    def __cinit__(self):
        self.derivedptr = self.thisptr = new DerivedClass()
    

    然后,当你需要访问派生类的方法时,使用派生指针代替。

    确保在解除分配时,您只删除派生指针。

    我从Cython Users mailing list 上的讨论中得到了这个想法。

    【讨论】:

    • 所以我尝试了你上面的解决方案,它在构建时给了我错误,因为它仍然认为它是一个 BaseClass * 指针。例如,错误是:** BaseClass 类型的对象没有属性 SetObject ** 我有一个临时的类型转换解决方法,但如果有更清洁的解决方案,我更愿意
    • @jeet.m 更新以解释如何解决所有类型转换。
    • 嗯..这是个好主意,所以如果我有一个派生类链,这是否意味着我需要为每个派生阶段/级别重新声明一种新类型的“派生ptr” ? (即,derivedptr1、derivedptr2 等)。如果是这样,您认为这是比类型转换更清洁的解决方案吗?只想知道您认为更好的解决方案,而不是怀疑您的答案:)
    • 完美,有效,非常感谢!你对我的问题的第二部分有什么想法,关于能够将 PyDerivedClass 对象作为函数输入参数传递吗?
    • 如果你有多个继承自同一个基类的类,那肯定会更干净。就清洁度而言,如果您有很多相互继承的类,我只需保留一个基类指针,然后为每个为我进行强制转换的类声明一个属性(与每个类类似地命名)。 docs 描述了如何声明属性。这将避免携带一堆不同的指针,但它会在每个类中添加几行额外的代码。不过,这只是一个想法。
    猜你喜欢
    • 2012-01-31
    • 2010-10-11
    • 2014-10-20
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2017-03-31
    相关资源
    最近更新 更多