我有一个小型 C++ 应用程序,我导入了 Objective-C 类。 它以 Objective-C++ 文件 .mm 的形式工作,但任何包含头文件(最终可能包含一些 Objective-C 头文件)的 C++ 文件都必须重命名为 .mm 扩展名,以适应正确的 GCC 驱动程序。
有没有办法为 Objective-C 类编写一个纯 C++ 包装器,或者我可以以某种方式将 Objective-C 对象分离出来并单独链接它们吗? 也许即使 Objective-C 类成为一个小库,我也可以在编译时静态地重新链接?
问题在于这段代码是跨平台的,并且在通常不使用 Objective-C 的系统(即非 Mac)上编译起来更加困难。 即使预处理器命令限制 Objective-C 代码在 Windows 或 Linux 上的任何实现,原始代码仍然具有 .mm 扩展名,并且 GCC 仍然将代码视为 Objective-C++。
通常你只需用 C++ 类包装你的 Objective-C 类,例如:使用不透明指针并将对 C++ 方法的调用转发给 Objective-C 方法。
这样,您的可移植 C++ 源代码永远不必看到任何 Objective-C 包含内容,理想情况下您只需更换不同平台上包装器的实现文件即可。
示例:
// c++ header:
class Wrapper {
struct Opaque;
Opaque* opaque;
// ...
public:
void f();
};
// Objective-C++ source on Mac:
struct Wrapper::Opaque {
id contained;
// ...
};
void Wrapper::f() {
[opaque->contained f];
}
// ...
是的,如果您知道一些技巧,这两种方式都很容易做到:
1) “id”类型实际上是在普通的 C 头文件中定义的。所以你可以执行以下操作:
在你的标题中:
#include <objc/objc.h>
class MyWindow
{
public:
MyWindow();
~MyWindow();
protected:
id mCocoaWindow;
};
在您的实施中(.mm):
#include "MyWindow.h"
#include <Cocoa/Cocoa.h>
MyWindow::MyWindow()
{
mCocoaWindow = [[NSWindow alloc] init];
}
MyWindow::~MyWindow()
{
[mCocoaWindow release];
mCocoaWindow = nil;
}
2) 当源文件包含两个预处理器常量(但不是 ObjC++ 之一)时,您可以使用两个预处理器常量来排除 C++/ObjC 特定代码:
#if __OBJC__
// ObjC code goes here.
#endif /* __OBJC__*/
#if __cplusplus
// C++ code goes here.
#endif
请小心,您不能仅使用 #ifdef 添加/删除 ivars 或虚拟方法,这将创建两个具有不同内存布局的类,并使您的应用程序以非常奇怪的方式崩溃。
3)您可以使用指向结构的指针而不声明其内容:
在你的标题中:
@interface MyCppObjectWrapper : NSObject
{
struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++.
}
@end
在您的实施文件 (.mm) 中:
struct MyCppObjectWrapperIVars
{
std::string myCppString1;
std::string myCppString2;
std::string myCppString3;
};
@implementation MyCppObjectWrapper
-(id) init
{
if(( self = [super init] ))
{
ivars = new MyCppObjectWrapperIVars;
}
return self;
}
-(void) dealloc
{
delete ivars;
ivars = NULL;
[super dealloc];
}
@end
这将使您的标头成为简单的标准 C 或 ObjC,而您的实现文件将获取所有调用的 ivars 的构造函数/析构函数,而无需将每个 ivars 作为堆上的对象创建/删除。
这只是 Mac 方面的事情,但这意味着您可以将 ObjC 内容保留在标头之外,或者至少在从 C++ 可移植层的 Mac 实现的跨平台客户端文件中使用它时进行编译.