Use C++ with Cocoa Instead of Objective-C?

86,726

Solution 1

You cannot write a Cocoa application entirely in C++. Cocoa relies heavily on the late binding capabilities of Objective-C for many of its core technologies such as Key-Value Bindings, delegates (Cocoa style), and the target-action pattern. The late binding requirements make it very difficult to implement the Cocoa API in a compile-time bound, typed language like C++ⁱ. You can, of course, write a pure C++ app that runs on OS X. It just can't use the Cocoa APIs.

So, you have two options if you want to share code between C++ apps on other platforms and your Cocoa-based application. The first is to write the model layer in C++ and the GUI in Cocoa. This is a common approach used by some very large apps, including Mathematica. Your C++ code can be left unchanged (you do not need "funky" apple extensions to write or compile C++ on OS X). Your controller layer will likely make use of Objective-C++ (perhaps the "funky" Apple extension you refer to). Objective-C++ is a superset of C++, just as Objective-C is a superset of C. In Objective-C++, you can make objc-style message passing calls (like [some-objc-object callMethod];) from within a C++ function. Conversely, you can call C++ functions from within ObjC code like:

@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

You can find out more about Objective-C++ in the Objective-C language guide. The view layer can then be pure Objective-C.

The second option is to use a cross-platform C++ toolkit. The Qt toolkit might fit the bill. Cross-platform toolkits are generally despised by Mac users because they do not get all the look and feel details exactly right and Mac users expect polish in the UI of Mac applications. Qt does a surprisingly good job, however, and depending on the audience and the use of your app, it may be good enough. In addition, you will lose out on some of the OS X-specific technologies such as Core Animation and some QuickTime functionality, though there are approximate replacements in the Qt API. As you point out, Carbon will not be ported to 64-bit. Since Qt is implemented on Carbon APIs, Trolltech/Nokia have had to port Qt to the Cocoa API to make it 64-bit compatible. My understanding is that the next relase of Qt (currently in release candiate) completes this transition and is 64-bit compatible on OS X. You may want to have a look at the source of Qt 4.5 if you're interested in integrating C++ and the Cocoa APIs.


ⁱ For a while Apple made the Cocoa API available to Java, but the bridge required extensive hand-tuning and was unable to handle the more advanced technologies such as Key-Value Bindings described above. Currently dynamically typed, runtime-bound languages like Python, Ruby, etc. are the only real option for writing a Cocoa app without Objective-C (though of course these bridges use Objective-C under the hood).

Solution 2

Well, it may sound silly, but actually we can write pure C++ code to create GUI for Mac OS X, but we must link against Cocoa framework.

/*
 * 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;
}

Solution 3

Yes, you can just use C++ (i.e. writing it in *.cpp files) and even mix C++ and Objective-C inside *.mm files (standard Objective-C code is stored in *.m files).

Of course, you still have to use Objective-C for your user-interface and create Objective-C wrappers for your C++ objects. Another option is to switch to Qt which is a C++ Framework that supports Windows, Mac OS X, and Linux -- and will be released under the LGPL with the next version 4.5.

Solution 4

Yes you can mix them.

You need to use Objective-C to directly operate on your GUI objects and receive notifications from them.

These Objective-C objects can directly call C++ logic if you put them in .mm files, instead of the pure Objective-C .m files. Note that you may see (much) older advice suggesting using an uppercase .M to indicate Objective-C++ but this is very flaky and likely to confuse you as well as the compiler.

You don't need to wrap each and every C++ object but your Objective-C code will need to contain pointers to them.

Apple no longer publish any samples showing how to do this.

There's a great video by Peter Steinberger hosted at Realm [Objective] C++: What Could Possibly Go Wrong? I highly recommend for anyone still using Objective-C++ and you can quickly skim the transcript.

Solution 5

If you're just looking to use plain vanilla C++, this is absolutely supported and really no different than any other platform. Xcode even has a template for it under File > New Project > Command Line Utility > C++ Tool. Also, a number of the popular open-source libraries (libcurl, libxml2, sqlite, etc) come with OS X and are available for dynamic linking. You don't have to use Cocoa or anything Apple-specific if you don't want to.

If you do want to use Cocoa in certain portions of your app, take a look at Objective-C++. You can mix C++ and Objective-C in the same file by giving it an extension of .mm, or by right-clicking on the file in Xcode and selecting Get Info > General then changing the File Type to sourcecode.cpp.objcpp. The second option is useful if you have a .cpp file where you want to use Objective-C within a Mac-specific #ifdef.

Share:
86,726
Brock Woolf
Author by

Brock Woolf

I predominantly code in Objective-C (Cocoa Touch) and C# (.net) I write games and utility software and do iPhone and iPad development. More here: BrockWoolf.com.

Updated on August 23, 2020

Comments

  • Brock Woolf
    Brock Woolf almost 4 years

    I would like to write applications that use C++ and the Cocoa frameworks because Apple is not making Carbon 64-bit capable. C++ seems to be pretty vanilla in its implementation on Linux and Windows but on Mac OS X it seems like additional Apple specific pieces of code are required (like an Obj-C wrapper). It also seems that Apple is forcing developers to write in Objective-C rather than C++, although I could be wrong.

    I am trying to find a path to write code on the Mac that would be easy to keep cross platform. Having to write code in C++ for Linux/Windows and then rewrite large portions in Objective-C would be very inefficient.

    Is there a way to write code in C++ that will be supported for the future and supported in Xcode? Also, if this is possible, how would I mix C++ and Objective-C in Xcode? Thanks.

  • Nico
    Nico over 15 years
    Note that if you use Qt, your app will suck. Qt-based apps do not look and feel like native Mac apps. (For an example, see Google Earth.)
  • fhe
    fhe over 15 years
    Yes, this is probably a trade-off you'll have to make. It's the price you pay for the reduced development effort :-)
  • Mike McQuaid
    Mike McQuaid over 14 years
    Peter: That's not true at all. Qt-based apps can look and feel identical to native Mac apps, you just need to do per-platform tweaking, something that is much easier than writing a native GUI on each platform.
  • NSResponder
    NSResponder over 14 years
    Mike, you are misinformed. Among their other shortcomings, Qt-based apps on the mac do not use the native controls at all, and the Qt library does all of the drawing itself. This means that Qt apps don't get any hardware acceleration for 2D rendering, they don't stay in sync with UI changes that Apple makes to the standard controls, and a Qt app can't deliver ADA compliance or scriptability unless you reinvent those wheels yourself. In other words, DO NOT ATTEMPT to ship a Qt app on the Mac. Google can get away with it: you can't.
  • Mike McQuaid
    Mike McQuaid over 13 years
    They do use the native controls, that's why Qt has a Cocoa and Carbon version. It has other issues but plenty of people ship Qt applications on Mac and they work fine (and perfectly with a bit of tweaking).
  • StNickolay
    StNickolay over 12 years
    fhe: please don't tangle two abbreviations, usually QT(big letters) means - QuickTime, but Qt - Nokia Qt framework
  • johnathan
    johnathan about 12 years
    @MikeMcQuaid and the rest , Gui preferences of users , and the visual polish that users of systems have came to expect are tremendous. And anytime you talk 'cross platform' solutions there's always those of the platform your targeting screaming about how the library your considering using 'sucks'. Most of the time , those comments are uninformed. And doing painting in Qt is easy to accomplish, as is most other things in the framework.
  • johnathan
    johnathan about 12 years
    @MikeMcQuaid Honestly, the only down side to using Qt from any perspective i can see is having to evaluate the tradeoff's of having to ship the Qt libs along with the exe. (and OpenGL, if you want a fancy hardware rendered UI)
  • eonil
    eonil over 11 years
    Just using of native control doesn't mean it will look and feel like native apps. What makes a native feeling is difference of each OS. If you tune your app to be felt in a specific platform, it won't be felt native on another platform. And, fine-tuning of small behaviors on once abstracted layer is always harder than doing it on native layer.
  • jokoon
    jokoon over 11 years
    I'm currently trying to port my small Ogre3D application, seems VERY painful. Is apple trying to convert everyone to Objc, or is this really a feature ?
  • imallett
    imallett almost 11 years
    This is wonderful. Are there more complicated examples available? For example, opening a NSWindow?
  • Jichao
    Jichao over 10 years
    test1.cpp: In function 'int main(int, char**)': test1.cpp:26:48: error: cannot convert 'Class {aka objc_class*}' to 'id {aka objc_object*}' in initialization id pool = objc_getClass("NSAutoreleasePool"); ^ test1.cpp:41:61: error: cannot convert 'Class {aka objc_class*}' to 'id {aka objc_object*}' for argument '1' to 'objc_object* objc_msgSend(id, SEL, ...)' sel_registerName("sharedApplication")); ^
  • Jay
    Jay over 10 years
    BTW, the (really useful) C++ template is gone with recent versions of Xcode (4.x and 5.x)
  • Dmitry Isaev
    Dmitry Isaev almost 10 years
    @Jichao see Clang compatibility with internal Objective-C types - the fix is simple: replace objc_getClass with (id)objc_getClass
  • fferri
    fferri almost 6 years
    @SteveS your link is broken too
  • M.Hamza Ali
    M.Hamza Ali almost 6 years
    @fferi - Steinberger link above is fixed. Carbon Cocoa Integration was from 2007 from developer.apple.com, Apple removed it. This indicates that you REALLY should not be writing new code using Carbon APIs. At this point, even maintaining existing code using Carbon is risky. Refer to the accepted answer for this question, or this one if you need to mix C++/Objective C, but you should not be using Carbon. That said, here: Carbon-Cocoa-Integration
  • Admin
    Admin over 4 years
    How can I use an std::string to set eg. the title for the alert panel? I tried using c_str() and alike but nothing worked...
  • Admin
    Admin about 4 years
    This doesn't compile anymore in macOS Catalina
  • Dinsdale
    Dinsdale about 3 years
    neither in Big Sur