如何使用C++类与cType?

2024-05-19 00:03:50 发布

您现在位置:Python中文网/ 问答频道 /正文

<>我刚刚开始使用cType,希望使用一个C++类,我使用Cype在Python中导出了一个DLL文件。 所以让我说我的C++代码看起来像这样:

class MyClass {
  public:
    int test();
...

我知道创建一个包含这个类的.dll文件,然后使用ctypes在python中加载.dll文件。 现在我如何创建一个MyClass类型的对象并调用它的测试函数?对ctypes来说这可能吗?或者我会考虑使用SWIG或Boost.Python,但是对于小项目来说,ctypes似乎是最简单的选择。


Tags: 文件对象代码test类型myclasspublicctype
3条回答

除了Booj.python(这可能是一个更友好的解决方案,它需要一个一对一的C++类到Python类的映射),可以在C++端提供一个C接口。这是许多解决方案中的一个,所以它有自己的折衷方案,但我将为那些不熟悉这项技术的人介绍它。对于完全公开,使用这种方法,一个不会连接C++到Python,而是C++到C到Python。下面我介绍了一个满足您的需求的例子,向您展示C++编译器的外部“C”设施的总体思路。

//YourFile.cpp (compiled into a .dll or .so file)
#include <new> //For std::nothrow
//Either include a header defining your class, or define it here. 

extern "C"  //Tells the compile to use C-linkage for the next scope.
{
    //Note: The interface this linkage region needs to use C only.  
    void * CreateInstanceOfClass( void )
    {
        // Note: Inside the function body, I can use C++. 
        return new(std::nothrow) MyClass;
    }

    //Thanks Chris. 
    void DeleteInstanceOfClass (void *ptr)
    {
         delete(std::nothrow) ptr; 
    }

    int CallMemberTest(void *ptr)
    {

        // Note: A downside here is the lack of type safety. 
        // You could always internally(in the C++ library) save a reference to all 
        // pointers created of type MyClass and verify it is an element in that
        //structure. 
        //
        // Per comments with Andre, we should avoid throwing exceptions.  
        try
        {
            MyClass * ref = reinterpret_cast<MyClass *>(ptr);
            return ref->Test();
        }
        catch(...)
        {
           return -1; //assuming -1 is an error condition. 
        }
    }

} //End C linkage scope.

您可以使用

gcc -shared -o test.so test.cpp
#creates test.so in your current working directory.

在python代码中,您可以这样做(显示2.7中的交互式提示):

>>> from ctypes import cdll
>>> stdc=cdll.LoadLibrary("libc.so.6") # or similar to load c library
>>> stdcpp=cdll.LoadLibrary("libstdc++.so.6") # or similar to load c++ library
>>> myLib=cdll.LoadLibrary("/path/to/test.so")
>>> spam = myLib.CreateInstanceOfClass()
>>> spam
[outputs the pointer address of the element]
>>> value=CallMemberTest(spam)
[does whatever Test does to the spam reference of the object] 

我相信Boost.Python在幕后也做了一些类似的工作,但是也许理解较低层次的概念是有帮助的。如果您试图访问C++库的功能,而不需要一对一映射,我会更感兴趣。

<> P>关于C/C++交互的更多信息,请从Sun中查看这个页面:^ {A1}

answer by AudaAero非常好,但并不完整(至少对我来说)。

在我的系统(Debian Stretch x64 with GCC和G++6.3.0,Python 3.5.3)中,只要调用一个访问类的成员值的成员函数,就会出现segfults。 我通过将指针值打印到stdout来诊断,包装器中64位编码的void*指针在Python中用32位表示。因此,当它被传递回成员函数包装器时会出现大问题。

我找到的解决办法是改变:

spam = myLib.CreateInstanceOfClass()

进入

Class_ctor_wrapper = myLib.CreateInstanceOfClass
Class_ctor_wrapper.restype = c_void_p
spam = c_void_p(Class_ctor_wrapper())

因此缺少两件事:将返回类型设置为c_void_p(默认值为int)然后创建c_void_p对象(而不仅仅是整数)。

我希望我可以写一个评论,但我仍然缺乏27个代表点。

简短的故事是,C++中没有标准二进制接口,因为C++的不同的编译器由于名称的篡改和不同的处理库函数调用之间的堆栈而输出不同的二进制文件。

<> P> >遗憾的是,在EME>中,实际上没有一种可移植的方式来访问C++库EM>。但是,对于一个编译器来说,这不是问题。

This blog post还有一个简短的概述,说明为什么这项功能目前不起作用。也许在C++ 0x出来之后,我们会有C++的标准ABI?在此之前,您可能无法通过Python的^ {CD1}}访问C++类。

相关问题 更多 >

    热门问题