cython - 包装一个 cpp 类聚合另一个

Posted

技术标签:

【中文标题】cython - 包装一个 cpp 类聚合另一个【英文标题】:cython - wrap a cpp class aggregating an other 【发布时间】:2016-12-12 08:57:33 【问题描述】:

我想用 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;

海洋.hpp

#ifndef OCEAN_H
#define OCEAN_H
class Ocean 
    public:
        double _depth;
        double _rho;

        Ocean();
        virtual ~Ocean();
        void setwaterdepth(double d);
;
#endif

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

海洋.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:\MinGW\bin\gcc.exe -mdll -O -Wall -IC:\Python27\include -IC:\Python27\PC -c testclass.cpp -o build\temp.win32-2.7\Release\testclass.o
writing build\temp.win32-2.7\Release\test.def
C:\MinGW\bin\g++.exe -shared -s build\temp.win32-2.7\Release\test.o build\temp.win32-2.7\Release\testclass.o build\temp.win32-2.7\Release\test.def -LC:\Python27\libs -LC:\Python27\PCbuild -LC:\Python27\PC\VS9.0 -lpython27 -lmsv
cr90 -o E:\00-Projets\InWave\Couplage\PYW\C++\test3\test.pyd
build\temp.win32-2.7\Release\testclass.o:testclass.cpp:(.text+0x97): undefined reference to `Ocean::~Ocean()'
build\temp.win32-2.7\Release\testclass.o:testclass.cpp:(.text+0xa3): undefined reference to `Ocean::~Ocean()'
build\temp.win32-2.7\Release\testclass.o:testclass.cpp:(.text+0xe4): undefined reference to `Ocean::Ocean()'
build\temp.win32-2.7\Release\testclass.o:testclass.cpp:(.text+0xfa): undefined reference to `Ocean::Ocean()'
build\temp.win32-2.7\Release\testclass.o:testclass.cpp:(.text+0x11a): undefined reference to `Ocean::~Ocean()'
build\temp.win32-2.7\Release\testclass.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

【问题讨论】:

对不起!我已经编辑了错误日志,因为它是错误的。 : 已添加,但在生成的 test.cpp 文件中仍然出现错误。 它不会改变错误。 我试了一下,我只有一个设置错误。我注意到您忘记在testclass.cpp 中包含iostream,并且您没有提供Ocean 的实现。你为什么from ocean cimport Ocean?请注意,我对 cython 一无所知。 是的,我没有在帖子中包含 iostream,但它在我的代码中。我在想Ocean 的实现并不重要。我尝试 cimport Ocean,因为 TestClass 有一个属性 Ocean。 不导入会出现以下错误:In file included from test.cpp:259:0: testclass.hpp:7:9: error: 'Ocean' does not name a type Ocean _ocean: 【参考方案1】:

我终于成功了。

无需包装 Ocean 类,因此无需为其创建 .pxd 文件。 但在 setup.py 中,包含所有 .cpp 依赖项很重要。

正如之前的 cmets 所说,在头文件中添加包含保护也很重要。

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

海洋.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

【讨论】:

以上是关于cython - 包装一个 cpp 类聚合另一个的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?

使用 Cython 时如何将一个 C++ 类(引用)传递给另一个?

聚合关系C ++中另一个类中的一个类的静态对象

cython wrap cpp 结构和函数,参数为结构数组

如何在 cython 模块中使用外部包装类?

如何在 python 包装中使用 unicode 字符串用于带有 cython 的 c++ 类?