结合使用C ++和Cocoa而非Objective-C?


122

我想编写使用C ++和Cocoa框架的应用程序,因为Apple并未使Carbon具备64位功能。C ++在Linux和Windows上的实现似乎很原始,但在Mac OS X上似乎需要附加的Apple特定代码段(如Obj-C包装程序)。尽管我可能错了,但苹果似乎也在强迫开发人员使用Objective-C而不是C ++进行编写。

我正在尝试寻找一种在Mac上编写代码的方法,该方法很容易保持跨平台。必须为Linux / Windows用C ++编写代码,然后再用Objective-C重写大部分代码,效率非常低下。

有没有一种方法可以用C ++编写将来会受Xcode支持的代码?另外,如果有可能,我该如何在Xcode中混合使用C ++和Objective-C?谢谢。

Answers:


110

您不能完全用C ++编写Cocoa应用程序。Cocoa的许多核心技术(例如键-值绑定,委托(Cocoa风格)和目标操作模式)在很大程度上依赖于Objective-C的后期绑定功能。后期绑定的要求,因此非常难以实现的约束编译时可可API,类型的语言,如C ++ⁱ。当然,您可以编写一个在OS X上运行的纯C ++应用程序。它不能使用Cocoa API。

因此,如果要在其他平台上的C ++应用程序和基于Cocoa的应用程序之间共享代码,则有两个选择。首先是用C ++编写模型层,并用Cocoa编写GUI。这是某些大型应用程序(包括Mathematica)使用的常见方法。您的C ++代码可以保持不变(您不需要“笨拙的” Apple扩展名即可在OS X上编写或编译C ++)。您的控制器层可能会使用Objective-C ++(也许是您所指的“笨拙” Apple扩展名)。正如Objective-C是C的超集一样,Objective-C ++是C ++的超集。在Objective-C ++中,您可以[some-objc-object callMethod];在C ++函数中进行objc样式的消息传递调用(如)。相反,您可以从ObjC代码中调用C ++函数,例如:

@interface MyClass {
    MyCPPClass *cppInstance;
}
@end

@implementation MyClass
- (id)init {
    if(self = [super init]) {
        cppInstance = new MyCPPClass();
    }
    return self;
}
- (void) dealloc {
    if(cppInstance != NULL) delete cppInstance;
    [super dealloc];
}
- (void)callCpp {
    cppInstance->SomeMethod();
}
@end

您可以在《 Objective-C语言指南》中找到有关Objective-C ++的更多信息。这样,视图层可以是纯Objective-C。

第二种选择是使用跨平台的C ++工具箱。在Qt的工具包可能符合要求。Mac用户通常鄙视跨平台工具包,因为它们不能完全正确地获得所有外观细节,并且Mac用户希望Mac应用程序的UI能够得到完善。Qt做得非常好,但是,取决于受众和您的应用程序的使用,它可能已经足够好了。此外,尽管Qt API中有大约替代品,但您将失去某些OS X特定技术,例如Core Animation和某些QuickTime功能。如您所指出,Carbon将不会移植到64位。由于Qt是在Carbon API上实现的,因此Trolltech /诺基亚不得不将Qt移植到Cocoa API上以使其与64位兼容。我的理解是Qt的下一个释放(当前处于候选版本中))完成了此过渡,并且在OS X上是64位兼容的。如果您对集成C ++和Cocoa API感兴趣,则可能需要看一下Qt 4.5的源代码。


Apple一段时间以来,Apple使Cocoa API可用于Java,但该桥接器需要进行大量的手动调整,并且无法处理上述更高级的技术,例如键-值绑定。当前动态类型化的,运行时绑定的语言(如Python,Ruby等)是编写不带Objective-C的Cocoa应用程序的唯一真实选择(尽管这些桥在后台使用了Objective-C)。


我目前正在尝试移植我的小型Ogre3D应用程序,似乎非常痛苦。苹果是在尝试将所有人都转换成Objc,还是这真的是一项功能?
jokoon

68

好吧,这听起来很愚蠢,但是实际上我们可以编写纯C ++代码为Mac OS X创建GUI,但是我们必须链接到Cocoa框架。

/*
 * test1.cpp
 * This program shows how to access Cocoa GUI from pure C/C++
 * and build a truly functional GUI application (although very simple).
 * 
 * Compile using:
 *   g++ -framework Cocoa -o test1 test1.cpp
 *
 * that will output 'test1' binary.
 */


#include <CoreFoundation/CoreFoundation.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <iostream>

extern "C" int NSRunAlertPanel(CFStringRef strTitle, CFStringRef strMsg,
                               CFStringRef strButton1, CFStringRef strButton2, 
                               CFStringRef strButton3, ...);


int main(int argc, char** argv)
{
    id app = NULL;
    id pool = (id)objc_getClass("NSAutoreleasePool");
    if (!pool)
    {
        std::cerr << "Unable to get NSAutoreleasePool!\nAborting\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("alloc"));
    if (!pool)
    {
        std::cerr << "Unable to create NSAutoreleasePool...\nAborting...\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("init"));

    app = objc_msgSend((id)objc_getClass("NSApplication"),
                       sel_registerName("sharedApplication"));

    NSRunAlertPanel(CFSTR("Testing"),
                    CFSTR("This is a simple test to display NSAlertPanel."),
                    CFSTR("OK"), NULL, NULL);

    objc_msgSend(pool, sel_registerName("release"));
    return 0;
}

16
太好了 是否有更复杂的示例可用?例如,打开NSWindow?
imallett

test1.cpp:在函数'int main(int,char **)'中:test1.cpp:26:48:错误:无法在初始化ID中将'Class {aka objc_class *}'转换为'id {aka objc_object *}'池= objc_getClass(“ NSAutoreleasePool”); ^ test1.cpp:41:61:错误:无法将参数'1'的'Class {aka objc_class *}'转换为'id {aka objc_object *}'到'objc_object * objc_msgSend(id,SEL,...)' sel_registerName(“ sharedApplication”)); ^
Jichao 2014年

6
@Jichao看到Clang与内部Objective-C类型的兼容性-修复很简单:替换objc_getClass(id)objc_getClass
Dmitry Isaev 2014年

如何使用std :: string设置例如。警报面板的标题?我尝试使用c_str()之类的方法,但无济于事……
mdre

1
这不再在macOS Catalina中编译
JC Rocamonde

18

是的,您可以只使用C ++(即以* .cpp文件编写),甚至可以在* .mm文件中混合使用C ++和Objective-C(标准的Objective-C代码存储在* .m文件中)。

当然,您仍然必须在用户界面上使用Objective-C,并为C ++对象创建Objective-C包装器。另一个选择是切换到Qt,它是一个支持Windows,Mac OS X和Linux的C ++框架-并将在LGPL下一个版本4.5下发布。


22
请注意,如果您使用Qt,您的应用程序将无法正常运行。基于Qt的应用看起来和感觉都不像本地Mac应用。(例如,请参阅Google Earth。)
Peter Hosey,

15
彼得:完全不是真的。基于Qt的应用程序在外观上与本机Mac应用程序相同,您只需要按平台进行调整,这比在每个平台上编写本机GUI容易得多。
Mike McQuaid

11
迈克,你误会了。在它们的其他缺点中,Mac上基于Qt的应用程序根本不使用本机控件,而Qt库本身完成了所有绘图。这意味着Qt应用程序无法获得2D渲染的任何硬件加速,它们不会与Apple对标准控件所做的UI更改保持同步,并且Qt应用程序无法提供ADA合规性或脚本性,除非您重新发明那些使自己动起来。换句话说,请勿尝试在Mac上发布Qt应用。Google可以摆脱它:您不能。
NSResponder

13
他们确实使用本机控件,这就是Qt具有可可和碳素版本的原因。它还有其他问题,但是很多人在Mac上发布了Qt应用程序,并且它们运行良好(并且进行了一些微调)。
Mike McQuaid

2
只需使用本机的控制并不意味着它的外观和感觉像本地应用程序。每个操作系统的不同之处在于产生原生的感觉。如果您将应用程序调整为在特定平台上使用,则不会在其他平台上使用它。而且,微调曾经抽象过的层上的小行为总是比在本机层上进行微调更困难。
凌晨

9

是的,您可以将它们混合。

您需要使用Objective-C直接在GUI对象上进行操作并接收来自它们的通知。

如果将这些Objective-C对象放入.mm文件而不是纯Objective-C .m文件,则它们可以直接调用C ++逻辑。请注意,您可能会看到(很多)较旧的建议,建议使用大写的.M表示Objective-C ++,但这非常不便,可能会使您和编译器感到困惑。

您不需要包装每个C ++对象,但是您的Objective-C代码将需要包含指向它们的指针。

Apple不再发布任何示例说明如何执行此操作。

彼得·斯坦伯格(Peter Steinberger)在Realm上录制了一段很棒的视频[目标] C ++:可能出错的地方是什么?我强烈建议仍然使用Objective-C ++的任何人,您可以快速浏览成绩单。


@SteveS您的链接也断开了
fferri 18'Aug

@fferi-上面的Steinberger链接是固定的。Carbon Cocoa Integration是2007年来自developer.apple.com的内容,Apple删除了它。这表明您实际上不应该使用Carbon API编写新代码。在这一点上,即使使用Carbon维护现有代码也是有风险的。请参阅接受的答案对于这个问题,或者这一个 ,如果你需要混合C ++ / Objective C的,但你不应该使用碳。就是说,这里:碳可可整合
-SteveS

4

如果您只是想使用普通的香草C ++,则绝对支持此功能,并且与任何其他平台都没有什么不同。Xcode甚至在“文件”>“新建项目”>“命令行实用程序”>“ C ++工具”下为其提供了模板。另外,OS X附带了许多流行的开源库(libcurl,libxml2,sqlite等),可用于动态链接。如果不想,您不必使用Cocoa或任何Apple特有的东西。

如果您确实想在应用程序的某些部分中使用Cocoa,请查看Objective-C ++。您可以通过将C ++和Objective-C扩展名为.mm或在Xcode中右键单击该文件并选择“获取信息”>“常规”,然后将“文件类型”更改为sourcecode.cpp.objcpp来将其混合使用。如果您有一个.cpp文件,并且要在Mac专用的#ifdef中使用Objective-C,则第二个选项很有用。


1
顺便说一句,(真正有用的)C ++模板与Xcode的最新版本(4.x和5.x)一起消失了
Jay

1

虽然这是一个古老的问题...

试图做一些Cocoa类的C ++包装器

这是非常不错的经验。C ++提供了比Objective-C更好的类型安全性,并使我编写的代码更少。但是编译时间和内存安全性更差。可以,但是一些基于动态的功能不容易处理。我认为在C ++上处理它没有任何意义。

无论如何,由于Swift的发布,我的项目最终被放弃了。它清除了我最初想使用C ++的所有原因,并且提供了更多更好的功能。


0

如果要编写纯图形应用程序,即要使用代码绘制所有内容,请考虑使用openFrameworks。这是一种基于C / C ++的开源图形化编程语言。它具有允许人们扩展语言的插件。他们有iPhone的插件。我相信它带有库和XCode项目,它们将帮助您编译iPhone和iPod touch的应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.