繁体   English   中英

我可以在编译和链接中将C ++主函数和类与Objective-C和/或C例程分开吗?

[英]Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

我有一个小的C ++应用程序,我导入了Objective-C类。 它可用作Objective-C ++文件,.mm,但任何包含可能最终包含某些Objective-C标头的标头的C ++文件必须重命名为.mm扩展名,以获取正确的GCC驱动程序。

有没有办法为Objective-C类编写一个纯粹的C ++包装器,或者我可以将Objective-C对象分开,并将它们分开链接? 也许即使Objective-C类成为一个小型库,我可以在编译时静态重新链接?

问题是这个代码是跨平台的,并且在通常不使用Objective-C(即不是Mac)的系统上编译更加困难。 即使预处理器命令限制在Windows或Linux上实现Objective-C代码,原始代码仍然具有.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)有两个预处理器常量可以用来排除C ++ / ObjC特定的代码,当源文件包含它们时,它们是两个中的一个,而不是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的构造函数/析构函数,而无需创建/删除每个作为堆上的对象。

这只是Mac方面的事情,但这意味着您可以将ObjC内容保留在标题之外,或者至少在从C ++可移植性层的Mac实现的跨平台客户端文件中使用时进行编译。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM