与来自 Swift 的 C++ 类交互
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35229149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interacting with C++ classes from Swift
提问by David Hoelzer
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.
我有一个用 C++ 编写的重要类库。我试图通过 Swift 中的某种类型的桥梁来使用它们,而不是将它们重写为 Swift 代码。主要动机是 C++ 代码代表在多个平台上使用的核心库。实际上,我只是创建了一个基于 Swift 的 UI,以允许核心功能在 OS X 下工作。
There are other questions asking, "How do I call a C++ function from Swift." This is notmy question. To bridge to a C++ function, the following works fine:
还有其他问题在问“我如何从 Swift 调用 C++ 函数”。这不是我的问题。要桥接到 C++ 函数,以下工作正常:
Define a bridging header through "C"
通过“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
Swift 代码现在可以直接调用函数
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++ Classfrom within Swift? I can't seem to find anything published on this.
我的问题更具体。如何从 Swift 中实例化和操作C++ 类?我似乎找不到关于此的任何内容。
采纳答案by David Hoelzer
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:
首先,获取您的 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);
};
We then implement these C++ functions:
然后我们实现这些 C++ 函数:
#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:
在 Swift 中,我们现在可以实例化对象并与之交互,如下所示:
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.
虽然这是一个美妙的开始,并证明使用现有的 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!
清理它只是意味着我们UnsafeMutablePointer<Void>
从 Swift 代码的中间删除了并将其封装到 Swift 类中。本质上,我们使用相同的 C/C++ 包装函数,但将它们与 Swift 类连接。Swift 类维护对象引用,本质上只是将所有方法和属性引用调用通过桥传递给 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 桥接器,但我们可以有效地透明地使用 C++ 对象,而不必求助于在 Objective-C 或 Objective-C++ 中重新编码它们。
回答by Catfish_Man
Swift has no C++ interop currently. It's a long-term goal, but is very unlikely to happen in the near future.
Swift 目前没有 C++ 互操作。这是一个长期目标,但在不久的将来不太可能实现。
回答by Ahmed
In addition to your own solution, there is another way to do it. You can call or directly write C++ code in objective-c++.
除了您自己的解决方案之外,还有另一种方法可以做到。你可以在objective-c++中调用或直接编写c++代码。
So you can create an objective-C++ wrapper on top of your C++ code and create a suitable interface.
因此,您可以在 C++ 代码之上创建一个目标 C++ 包装器并创建一个合适的接口。
Then call objective-C++ code from your swift code. To be able to write objective-C++ code you may have to rename file extension from .m to .mm
然后从您的 Swift 代码中调用 Objective-C++ 代码。为了能够编写 Objective-C++ 代码,您可能需要将文件扩展名从 .m 重命名为 .mm
Do not forget to release memory allocated by your C++ objects when suitable.
不要忘记在合适的时候释放 C++ 对象分配的内存。
回答by nnrales
As another answer mentioned, using ObjC++ to interact is much easier. Just name your files .mm instead of .m and xcode/clang, gives you access to c++ in that file.
正如另一个答案所提到的,使用 ObjC++ 进行交互要容易得多。只需将您的文件命名为 .mm 而不是 .m 和 xcode/clang,您就可以访问该文件中的 c++。
Note that ObjC++ does not support C++ inheritance. I you want to subclass a c++ class in ObjC++, you can't. You will have to write the subclass in C++ and wrap it around an ObjC++ class.
请注意,ObjC++ 不支持 C++ 继承。我想在 ObjC++ 中继承 c++ 类,你不能。您必须用 C++ 编写子类并将其包装在 ObjC++ 类中。
Then use the bridging header you would normally use to call objc from swift.
然后使用您通常用来从 swift 调用 objc 的桥接头。
回答by Boris Rasin
You can use Scapix Language Bridgeto automatically bridge C++ to Swift (among other languages). Bridge code automatically generated on the fly directly from C++ header files. Here is an example:
您可以使用Scapix Language Bridge自动将 C++ 桥接到 Swift(以及其他语言)。桥接代码直接从 C++ 头文件中自动生成。这是一个例子:
C++:
C++:
#include <scapix/bridge/object.h>
class contact : public scapix::bridge::object<contact>
{
public:
std::string name();
void send_message(const std::string& msg, std::shared_ptr<contact> from);
void add_tags(const std::vector<std::string>& tags);
void add_friends(std::vector<std::shared_ptr<contact>> friends);
};
Swift:
迅速:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}