Cython-包装CPP类,汇总另一个

cython - wrap a cpp class aggregating an other

本文关键字:另一个 包装 CPP Cython-      更新时间:2023-10-16

我想用Cython创建一个CPP类包装器。但是这个课程汇总了另一个课程,我不知道我是否还需要为此课程创建一个包装器,因为我不想从Python打电话。

有CPP类:

testclass.hpp

#ifndef TESTCLASS_H
#define TESTCLASS_H
#include "ocean.hpp"
class TestClass {
    private:
        Ocean _ocean;
    public:
        int x, y;
        TestClass();
        ~TestClass();
        int Multiply(int a, int b);
};
#endif

testclass.cpp

#include "testclass.hpp"
TestClass::TestClass()
{
    x = 5;
    y = 1;
    _ocean = Ocean();
}
TestClass::~TestClass()
{
    std::cout << "Calling destructor" << std::endl;
}
int TestClass::Multiply(int a, int b)
{
    return a*b;
}

Ocean.hpp

#ifndef OCEAN_H
#define OCEAN_H
class Ocean {
    public:
        double _depth;
        double _rho;
        Ocean();
        virtual ~Ocean();
        void setwaterdepth(double d);
};
#endif

我只想包装测试课,这是我尝试的:

Ocean.pxd

cdef extern from "ocean.hpp":
cdef cppclass Ocean:
    Ocean()

test.pyx

from ocean cimport Ocean
cdef extern from "testclass.hpp":
    cdef cppclass TestClass:
        TestClass()
        int x
        int y
        int Multiply(int a, int b)
cdef class pyTestClass:
    cdef TestClass* thisptr # hold a C++ instance
    def __cinit__(self):
        self.thisptr = new TestClass()
    def __dealloc__(self):
        del self.thisptr
    def Multiply(self, a, b):
        return self.thisptr.Multiply(a, b)

setup.py

from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("test",
                sources=["test.pyx", "testclass.cpp"],
                language="c++")
setup(name="test",
      ext_modules=cythonize(ext))

Q1)是正确的方法吗?(当我编译时,我会收到以下错误,但我不明白错误。)

C:MinGWbingcc.exe -mdll -O -Wall -IC:Python27include -IC:Python27PC -c testclass.cpp -o buildtemp.win32-2.7Releasetestclass.o
writing buildtemp.win32-2.7Releasetest.def
C:MinGWbing++.exe -shared -s buildtemp.win32-2.7Releasetest.o buildtemp.win32-2.7Releasetestclass.o buildtemp.win32-2.7Releasetest.def -LC:Python27libs -LC:Python27PCbuild -LC:Python27PCVS9.0 -lpython27 -lmsv
cr90 -o E:0-ProjetsInWaveCouplagePYWC++test3test.pyd
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0x97): undefined reference to `Ocean::~Ocean()'
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0xa3): undefined reference to `Ocean::~Ocean()'
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0xe4): undefined reference to `Ocean::Ocean()'
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0xfa): undefined reference to `Ocean::Ocean()'
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0x11a): undefined reference to `Ocean::~Ocean()'
buildtemp.win32-2.7Releasetestclass.o:testclass.cpp:(.text+0x196): undefined reference to `Ocean::~Ocean()'
collect2.exe: error: ld returned 1 exit status
error: command 'C:\MinGW\bin\g++.exe' failed with exit status 1

我最终设法使它起作用。

无需包装海洋类,因此为其创建.pxd文件。但是在setup.py中,包括所有.cpp依赖关系很重要。

如前所述,在标题文件中添加guard也很重要。

所以这是一个工作代码(用python setup.py build_ext --inplace编译)

Ocean.hpp

#ifndef OCEAN_H
#define OCEAN_H
class Ocean {
    public:
        double _depth;
        double _rho;
        Ocean();
        virtual ~Ocean();
        void setwaterdepth(double d);
};
#endif

testclass.hpp

#ifndef TESTCLASS_H
#define TESTCLASS_H
#include "ocean.hpp"
class TestClass {
    private:
        Ocean _ocean;
    public:
        int x, y;
        TestClass();
        virtual ~TestClass();
        int Multiply(int a, int b);
        void _set_x(int x);
};
#endif

testclass.cpp

#include <iostream>
#include "testclass.hpp"
#include "ocean.hpp"
TestClass::TestClass()
{
    x = 5;
    y = 1;
    _ocean = Ocean();
    std::cout << "Calling constructor" << std::endl;
}
TestClass::~TestClass()
{
    std::cout << "Calling destructor" << std::endl;
}
int TestClass::Multiply(int a, int b)
{
    return a*b;
}
void TestClass::_set_x(int new_x)
{
    x = new_x;
}

test.pyx

cdef extern from "testclass.hpp":
    cdef cppclass TestClass:
        TestClass()
        int x
        int y
        int Multiply(int a, int b)
cdef class pyTestClass:
    cdef TestClass* thisptr # hold a C++ instance
    def __cinit__(self):
        self.thisptr = new TestClass()
    def __dealloc__(self):
        del self.thisptr
    def Multiply(self, a, b):
        return self.thisptr.Multiply(a, b)
    property y:
        # Here we use a property to expose the public member
        # y of TestClass to Python
        def __get__(pyTestClass self):
            return self.thisptr.y
        def __set__(pyTestClass self, value):
            self.thisptr.y = <int> value

setup.py

from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("test",
            sources=["test.pyx", "testclass.cpp", "ocean.cpp"],
            language="c++")
setup(name="test", ext_modules=cythonize(ext))

包装的测试

import test as wrapper
T = wrapper.pyTestClass()
print T.Multiply(3, 5)
print T.y
T.y = 3
print T.y

输出

Calling ocean constructor
Calling ocean constructor
Calling ocean destructor
Calling constructor
15
1
3
Calling destructor
Calling ocean destructor