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

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

问题描述

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

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.

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

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:

通过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 代码现在可以直接调用函数

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

我的问题更具体.如何从 Swift 中实例化和操作 C++ 类?我似乎找不到关于此的任何内容.

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.

首先,使用您的 C++ 类并创建 C 的包装器"函数来与之交互.例如,如果我们有这个 C++ 类:

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);
};

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

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;
}

桥头包含:

#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 */

从 Swift 开始,我们现在可以像这样实例化对象并与之交互:

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.

让它更干净

虽然这是一个很棒的开始,并证明使用现有的 C++ 类和一个简单的桥接器是完全可行的,但它可以更简洁.

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.

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

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!

这样做之后,所有的桥接代码都完全封装在 Swift 类中.尽管我们仍在使用 C 桥接器,但我们可以有效地透明地使用 C++ 对象,而不必求助于在 Objective-C 或 Objective-C++ 中重新编码.

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天全站免登陆