将C++抽象类作为参数传递给Cython

3

如果我有一个抽象基类和一个从它继承的派生类,但是我有另一个以抽象基类对象作为参数的类,我该如何进行包装?

class A {
 public:
  A(int x, int y);
  virtual int FooA(int x, int y) = 0;
  virtual void FooB() = 0;

}

class B : public A{
  B(int x, int y, int z, int w);
  int FooA(int x, int y);
  void FooB();
  void FooC(int z, int w);
}

class C {
 public:
  C(A* ptr, int p);

}

我应该如何整体包装它?我知道不应该包装抽象类A,但是由于没有Python对象A,我很难包装C。

编辑:实际上我已经成功地包装了这个类,但我仍然遇到错误,稍后我将进一步说明。

source.pyx

cdef extern from "A.h"
   cdef cppclass A:
      A(int x, int y)
      int FooA(int x, int y)
      void FooB()  

cdef extern from "B.h"
   cdef cppclass B(A):  
      B(int x, int y, int z, int w)
      int FooA(int x, int y)
      void FooB()
      void FooC(int z, int w)  

cdef extern from "C.h"
   cdef cppclass C:
      C(A* ptr, int p)

cdef class pyA:
   cdef A* baseptr
   def __cinit__(self, int x, int y):
      if type(self) is A:
          self.baseptr = new A(int x, int y)

   def __dealloc__(self):
      if type(self) is A:
          del self.baseptr

   def FooA(self, int x, int y):
      pass

   def FooB(self):
      pass

cdef class pyB(pyA):
   def __cinit__(self, int x, int y, int z, int w):
      if type(self) is pyB:
         self.derivedptr = self.baseptr = new B(int x, int y, int z, int w) 
   def __dealloc__(self):
      del self.derivedptr 

   def FooC(self, int z, int w):
      self.derivedptr.FooC(int z, int w)

cdef class pyC:
   cdef C *thisptr
   def __cinit__(self, pyA ptr, int p):
      self.thisptr(<A *> ptr.thisptr, int p)
   def __dealloc__(self):
      del self.thisptr

当我测试pyC并将pyB作为第一个参数传递时,得到了以下结果:

TypeError: "Expected pyA, got pyB". 

既然pyB是pyA的子类,那么它不应该也能作为第一个参数传递吗?还是我理解错了?


你可以通过从 PyC.__cinit__ 中删除 PyA 类型说明符来消除剩余的错误。[还要更改强制转换为 <A*?>,以允许可能是错误类型的情况] - DavidW
1个回答

5

很抱歉回答晚了。但是对于那些可能感兴趣的人,这是可行的代码。

A.h

#ifndef A_H_
#define A_H_

class A {
public:
  virtual int FooA(int x, int y) = 0;
  virtual void FooB() = 0;
};

#endif /* A_H_ */

B.h

#ifndef B_H_
#define B_H_

#include "A.h"

class B : public A{
public:
  B(int x, int y, int z, int w);
  int FooA(int x, int y);
  void FooB();
  void FooC(int z, int w);
};

#endif /* B_H_ */

C.h

#ifndef C_H_
#define C_H_

#include "A.h"

class C {
 public:
  C(A* ptr, int p);
};

#endif /* C_H_ */

B.cpp

#include "B.h"
#include <iostream>

using namespace std;

B::B(int x, int y, int z, int w)
{
    cout << "B::B" << endl;
    cout << x << " " << y << " "
         << z << " " << w << endl;
}

int B::FooA(int x, int y)
{
    cout << "B::FooA" << endl;
    cout << x << " " << y << endl;
    return 0;
}

void B::FooB()
{
    cout << "B::FooB" << endl;
}

void B::FooC(int z, int w)
{
    cout << "B::FooC" << endl;
    cout << z << " " << w << endl;
}

C.cpp

#include "C.h"
#include <iostream>

using namespace std;

C::C(A* ptr, int p)
{
    cout << "C::C" << endl;
    cout << ptr->FooA(0,1) << endl;
    ptr->FooB();
}

source.pyx

# distutils: language = c++
# distutils: sources = [B.cpp, C.cpp]

cdef extern from "A.h":
   cdef cppclass A:
      A(int x, int y) except +
      int FooA(int x, int y)
      void FooB()  

cdef extern from "B.h":
   cdef cppclass B(A):  
      B(int x, int y, int z, int w) except +
      int FooA(int x, int y)
      void FooB()
      void FooC(int z, int w)  

cdef extern from "C.h":
   cdef cppclass C:
      C(A *ptr, int p) except +

cdef class pyA:
   cdef A *baseptr
   def __cinit__(self):
      pass

   def FooA(self, int x, int y):
      pass

   def FooB(self):
      pass

cdef class pyB(pyA):
   cdef B *derivedptr
   def __cinit__(self, int x, int y, int z, int w):
     self.derivedptr = new B(x, y, z, w)
     self.baseptr = self.derivedptr

   def __dealloc__(self):
      del self.derivedptr 

   def FooC(self, int z, int w):
      self.derivedptr.FooC(z, w)

cdef class pyC:
   cdef C *thisptr
   def __cinit__(self, pyA ptr, int p):
      self.thisptr = new C(ptr.baseptr, p)

   def __dealloc__(self):
      del self.thisptr

setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
    name = 'testapp',
    ext_modules = cythonize('*.pyx'),
)

最后,编译代码。
$python setup.py build_ext --inplace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接