我有一个用C++编写的重要类库.我试图通过Swift中的某种类型的桥来使用它们,而不是将它们重写为Swift代码.主要动机是C++代码表示在多个平台上使用的核心库.实际上,我只是创建一个基于Swift的UI,以允许核心功能在OS X下工作.
还有其他问题,"如何从Swift调用C++函数." 这不是我的问题.要桥接到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 */
Run Code Online (Sandbox Code Playgroud)
Swift代码现在可以直接调用函数
let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))
Run Code Online (Sandbox Code Playgroud)
我的问题更具体.如何在Swift中实例化和操作C++类?我似乎无法找到任何关于此的内容.
Dav*_*zer 56
我找到了一个完美可控的答案.你想要的多么干净完全取决于你愿意做多少工作.
首先,使用您的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);
};
Run Code Online (Sandbox Code Playgroud)
然后我们实现这些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;
}
Run Code Online (Sandbox Code Playgroud)
然后桥头包含:
#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 */
Run Code Online (Sandbox Code Playgroud)
从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!
Run Code Online (Sandbox Code Playgroud)
因此,正如您所看到的,解决方案(实际上相当简单)是创建将实例化对象并返回指向该对象的指针的包装器.然后可以将其传递回包装函数,该函数可以轻松地将其视为符合该类的对象并调用成员函数.
让它更清洁
虽然这是一个很棒的开始,并且证明使用现有的C++类与一个简单的桥是完全可行的,但它可以更清晰.
清理它只是意味着我们UnsafeMutablePointer<Void>从Swift代码的中间删除它并将其封装到Swift类中.本质上,我们使用相同的C/C++包装器函数,但将它们与Swift类接口.Swift类维护对象引用,基本上只是将所有方法和属性引用调用通过桥传递给C++对象!
完成此操作后,所有桥接代码都完全封装在Swift类中.即使我们仍在使用C桥,我们也可以透明地有效地使用C++对象,而无需在Objective-C或Objective-C++中重新编码它们.
Swift目前没有C++互操作.这是一个长期目标,但不太可能在不久的将来发生.
您可以使用Scapix Language Bridge自动将 C++ 桥接到 Swift(以及其他语言)。桥接代码直接从 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);
};
Run Code Online (Sandbox Code Playgroud)
迅速:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}
Run Code Online (Sandbox Code Playgroud)
除了您自己的解决方案,还有另一种方法可以做到这一点.您可以在objective-c ++中调用或直接编写C++代码.
因此,如果您在C++代码之上创建一个Objective-C++包装器并创建一个合适的接口
并从您的swift代码中调用objective-C++代码.为了能够编写Objective-C++代码,您可能必须将文件扩展名从.m重命名为.mm
在适当的时候,不要忘记释放由C++对象分配的内存.
正如提到的另一个答案,使用ObjC ++进行交互要容易得多。只需将文件命名为.mm而不是.m和xcode / clang,即可访问该文件中的c ++。
请注意,ObjC ++不支持C ++继承。我想在ObjC ++中继承c ++类,但是不能。您将不得不用C ++编写子类,并将其包装在ObjC ++类中。
然后使用通常用于从swift调用objc的桥接头。
| 归档时间: |
|
| 查看次数: |
40933 次 |
| 最近记录: |