与Swift中的C ++类交互 [英] Interacting with C++ classes from Swift

查看:112
本文介绍了与Swift中的C ++类交互的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个重要的用C ++编写的类库。我试图通过某种类型的桥梁在Swift中使用它们,而不是将它们重写为Swift代码。主要动机是C ++代码表示在多个平台上使用的核心库。实际上,我只是创建一个基于Swift的UI,以允许核心功能在OS X下工作。



还有其他问题,如何调用C ++函数从Swift。这是不是我的问题。要桥接到C ++函数,以下工作正常:



通过C定义桥接标题

  #ifndef ImageReader_hpp 
#define ImageReader_hpp

#ifdef __cplusplus
externC{
#endif

const char * hexdump(char * filename);
const char * imageType(char * filename);

#ifdef __cplusplus
}
#endif

#endif / * ImageReader_hpp * /
pre>

Swift代码现在可以直接调用函数

  let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))

我的问题更具体。如何在Swift中实例化和操作 C ++类?我似乎找不到任何发布的东西。

解决方案

我制定了一个完全可管理的答案。



首先,获取你的C ++类并创建C包装器功能与其接口。例如,如果我们有这个C ++类:

  class MBR {
std :: string filename;

public:
MBR(std :: string filename);
const char * hexdump();
const char * imageType();
const char * bootCode();
const char * partitions();
private:
bool readFile(unsigned char * buffer,const unsigned int length);
};

然后我们实现这些C ++函数:

  #includeMBR.hpp

using namespace std;
const void * initialize(char * filename)
{
MBR * mbr = new MBR(filename);

return(void *)mbr;
}

const char * hexdump(const void * object)
{
MBR * mbr;
static char retval [2048];

mbr =(MBR *)object;
strcpy(retval,mbr - > hexdump());
return retval;
}

const char * imageType(const void * object)
{
MBR * mbr;
static char retval [256];

mbr =(MBR *)object;
strcpy(retval,mbr - > imageType());
return retval;
}

桥头包含:

  #ifndef ImageReader_hpp 
#define ImageReader_hpp

#ifdef __cplusplus
externC{
#endif

const void * initialize(char * filename);
const char * hexdump(const void * object);
const char * imageType(const void * object);

#ifdef __cplusplus
}
#endif

#endif / * ImageReader_hpp * /
pre>

从Swift,我们现在可以实例化对象并与其交互:

  let cppObject = UnsafeMutablePointer< Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump )
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!

所以,你可以看到,解决方案将实例化一个对象并返回一个指向该对象的指针。这可以被传递回包装函数,它可以很容易地把它看作一个符合该类的对象并调用成员函数。



使它更清洁



虽然这是一个奇妙的开始,证明使用现有的C ++类和一个简单的桥是完全可行的,它可以更清洁。 >

清理这个只是意味着我们从Swift代码的中间删除 UnsafeMutablePointer 一个Swift类。基本上,我们使用相同的C / C ++包装函数,但它们与一个Swift类接口。 Swift类维护对象引用,本质上只是将所有方法和属性引用调用通过桥接传递给C ++对象!



完成这一步后,所有的桥接代码完全封装在Swift类中。即使我们仍在使用C桥,我们仍然可以透明地有效地使用C ++对象,而不必在Objective-C或Objective-C ++中重新编码。


I have a significant library of classes written in C++. I'm trying to make use of them through some type of bridge within Swift rather than rewrite them as Swift code. The primary motivation is that the C++ code represents a core library that is used on multiple platforms. Effectively, I'm just creating a Swift based UI to allow the core functionality to work under OS X.

There are other questions asking, "How do I call a C++ function from Swift." This is not my question. To bridge to a C++ function, the following works fine:

Define a bridging header through "C"

#ifndef ImageReader_hpp
#define ImageReader_hpp

#ifdef __cplusplus
extern "C" {
#endif

    const char *hexdump(char *filename);
    const char *imageType(char *filename);

#ifdef __cplusplus
}
#endif

#endif /* ImageReader_hpp */

Swift code can now call functions directly

let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))

My question is more specific. How can I instantiate and manipulate a C++ Class from within Swift? I can't seem to find anything published on this.

解决方案

I've worked out a perfectly manageable answer. How clean you'd like this to be is entirely based upon how much work you're willing to do.

First, take your C++ class and create C "wrapper" functions to interface with it. For example, if we have this C++ class:

class MBR {
    std::string filename;

public:
    MBR (std::string filename);
    const char *hexdump();
    const char *imageType();
    const char *bootCode();
    const char *partitions();
private:
    bool readFile(unsigned char *buffer, const unsigned int length);
};

We then implement these C++ functions:

#include "MBR.hpp"

using namespace std;
const void * initialize(char *filename)
{
    MBR *mbr = new MBR(filename);

    return (void *)mbr;
}

const char *hexdump(const void *object)
{
    MBR *mbr;
    static char retval[2048];

    mbr = (MBR *)object;
    strcpy(retval, mbr -> hexdump());
    return retval;
}

const char *imageType(const void *object)
{
    MBR *mbr;
    static char retval[256];

    mbr = (MBR *)object;
    strcpy(retval, mbr -> imageType());
    return retval;
}

The bridge header then contains:

#ifndef ImageReader_hpp
#define ImageReader_hpp

#ifdef __cplusplus
extern "C" {
#endif

    const void *initialize(char *filename);
    const char *hexdump(const void *object);
    const char *imageType(const void *object);

#ifdef __cplusplus
}
#endif

#endif /* ImageReader_hpp */

From Swift, we can now instantiate the object and interact with it like so:

let cppObject = UnsafeMutablePointer<Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump(cppObject))                
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!

So, as you can see, the solution (which is actually rather simple) is to create wrappers that will instantiate an object and return a pointer to that object. This can then be passed back into the wrapper functions which can easily treat it as an object conforming to that class and call the member functions.

Making It Cleaner

While this is a fantastic start and proves that it is completely feasible to use existing C++ classes with a trivial bridge, it can be even cleaner.

Cleaning this up would simply mean that we remove the UnsafeMutablePointer<Void> from the middle of our Swift code and encapsulate it into a Swift class. Essentially, we use the same C/C++ wrapper functions but interface them with a Swift class. The Swift class maintains the object reference and essentially just passes all method and attribute reference calls through the bridge to the C++ object!

Having done this, all of the bridging code is completely encapsulated in the Swift class. Even though we are still using a C bridge, we are effectively using C++ objects transparently without having to resort to recoding them in Objective-C or Objective-C++.

这篇关于与Swift中的C ++类交互的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆