Verwenden Sie C ++ mit Kakao anstelle von Objective-C?

122

Ich möchte Anwendungen schreiben, die C ++ und die Cocoa-Frameworks verwenden, da Apple Carbon 64-Bit nicht fähig macht. C ++ scheint in seiner Implementierung unter Linux und Windows ziemlich vanillig zu sein, aber unter Mac OS X scheinen zusätzliche Apple-spezifische Codeteile erforderlich zu sein (wie ein Obj-C-Wrapper). Es scheint auch, dass Apple Entwickler dazu zwingt, in Objective-C anstatt in C ++ zu schreiben, obwohl ich mich irren könnte.

Ich versuche, einen Pfad zum Schreiben von Code auf dem Mac zu finden, der einfach plattformübergreifend zu halten ist. Es wäre sehr ineffizient, Code in C ++ für Linux / Windows schreiben und dann große Teile in Objective-C neu schreiben zu müssen.

Gibt es eine Möglichkeit, Code in C ++ zu schreiben, der für die Zukunft und in Xcode unterstützt wird? Wenn dies möglich ist, wie würde ich C ++ und Objective-C in Xcode mischen? Vielen Dank.

Brock Woolf
quelle

Antworten:

110

Sie können eine Cocoa-Anwendung nicht vollständig in C ++ schreiben. Cocoa verlässt sich bei vielen seiner Kerntechnologien wie Schlüsselwertbindungen, Delegierten (Kakao-Stil) und dem Zielaktionsmuster stark auf die späten Bindungsfunktionen von Objective-C. Die späten Bindungsanforderungen machen es sehr schwierig, die Cocoa-API in einer zur Kompilierungszeit gebundenen, typisierten Sprache wie C ++ implement zu implementieren. Sie können natürlich eine reine C ++ - App schreiben, die unter OS X ausgeführt wird. Die Cocoa-APIs können einfach nicht verwendet werden.

Sie haben also zwei Möglichkeiten, wenn Sie Code zwischen C ++ - Apps auf anderen Plattformen und Ihrer Cocoa-basierten Anwendung freigeben möchten. Die erste besteht darin, die Modellebene in C ++ und die GUI in Cocoa zu schreiben. Dies ist ein gängiger Ansatz, der von einigen sehr großen Apps verwendet wird, einschließlich Mathematica . Ihr C ++ - Code kann unverändert bleiben (Sie benötigen keine "funky" Apple-Erweiterungen, um C ++ unter OS X zu schreiben oder zu kompilieren). Ihre Controller-Schicht wird wahrscheinlich Objective-C ++ verwenden (möglicherweise die "funky" Apple-Erweiterung, auf die Sie sich beziehen). Objective-C ++ ist eine Obermenge von C ++, genau wie Objective-C eine Obermenge von C. In Objective-C ++ können Sie [some-objc-object callMethod];innerhalb einer C ++ - Funktion Aufrufe zum Weiterleiten von Nachrichten im Objektstil (wie ) ausführen . Umgekehrt können Sie C ++ - Funktionen aus dem ObjC-Code heraus aufrufen, z.

@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

Sie können mehr über Objective-C ++ in der Objective-C - Sprache herausfinden Führung . Die Ansichtsebene kann dann reines Objective-C sein.

Die zweite Option ist die Verwendung eines plattformübergreifenden C ++ - Toolkits. Der QtToolkit könnte die Rechnung passen. Plattformübergreifende Toolkits werden von Mac-Benutzern im Allgemeinen verachtet, da sie nicht alle Details des Erscheinungsbilds genau richtig wiedergeben und Mac-Benutzer eine Verbesserung der Benutzeroberfläche von Mac-Anwendungen erwarten. Qt leistet jedoch überraschend gute Arbeit und kann je nach Zielgruppe und Verwendung Ihrer App gut genug sein. Darüber hinaus verlieren Sie einige der OS X-spezifischen Technologien wie Core Animation und einige QuickTime-Funktionen, obwohl die Qt-API ungefähr ersetzt wird. Wie Sie hervorheben, wird Carbon nicht auf 64-Bit portiert. Da Qt auf Carbon-APIs implementiert ist, mussten Trolltech / Nokia Qt auf die Cocoa-API portieren, um die 64-Bit-Kompatibilität zu gewährleisten. Mein Verständnis ist, dass die nächste Veröffentlichung von Qt (derzeit in Release Candiate)) schließt diesen Übergang ab und ist unter OS X 64-Bit-kompatibel. Wenn Sie an der Integration von C ++ und den Cocoa-APIs interessiert sind, sollten Sie sich die Quelle von Qt 4.5 ansehen.


ⁱ Für eine Weile stellte Apple die Cocoa-API Java zur Verfügung, aber die Bridge erforderte umfangreiche Hand-Tuning und war nicht in der Lage, die oben beschriebenen fortschrittlicheren Technologien wie Key-Value-Bindungen zu verarbeiten. Derzeit dynamisch typisierte, an die Laufzeit gebundene Sprachen wie Python, Ruby usw. sind die einzige echte Option zum Schreiben einer Cocoa-App ohne Objective-C (obwohl diese Bridges natürlich Objective-C unter der Haube verwenden).

Barry Wark
quelle
Ich versuche gerade, meine kleine Ogre3D-Anwendung zu portieren, scheint sehr schmerzhaft zu sein. Versucht Apple, alle auf Objc umzustellen, oder ist dies wirklich eine Funktion?
Jokoon
68

Nun, es mag albern klingen, aber tatsächlich können wir reinen C ++ - Code schreiben, um eine GUI für Mac OS X zu erstellen, aber wir müssen eine Verknüpfung mit dem Cocoa-Framework herstellen.

/*
 * 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;
}
FX. J. Adi Lima
quelle
16
Das ist wunderbar. Gibt es kompliziertere Beispiele? Zum Beispiel ein NSWindow öffnen?
Imallett
test1.cpp: In der Funktion 'int main (int, char **)': test1.cpp: 26: 48: Fehler: 'Klasse {aka objc_class *}' kann in der Initialisierungs-ID nicht in 'id {aka objc_object *}' konvertiert werden pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: Fehler: 'Klasse {aka objc_class *}' kann nicht in 'id {aka objc_object *}' für Argument '1' in 'objc_object * objc_msgSend (id, SEL, ...)' konvertiert werden. sel_registerName ("sharedApplication")); ^
Jichao
6
@Jichao siehe Clang-Kompatibilität mit internen Objective-C-Typen - die Korrektur ist einfach: Ersetzen objc_getClassdurch(id)objc_getClass
Dmitry Isaev
Wie kann ich einen std :: string verwenden, um z. der Titel für das Alarmfeld? Ich habe versucht, c_str () und dergleichen zu verwenden, aber nichts hat funktioniert ...
mdre
1
Dies wird in macOS Catalina
JC Rocamonde
18

Ja, Sie können einfach C ++ verwenden (dh in * .cpp-Dateien schreiben) und sogar C ++ und Objective-C in * .mm-Dateien mischen (Standard-Objective-C-Code wird in * .m-Dateien gespeichert).

Natürlich müssen Sie weiterhin Objective-C für Ihre Benutzeroberfläche verwenden und Objective-C-Wrapper für Ihre C ++ - Objekte erstellen. Eine weitere Option ist der Wechsel zu Qt , einem C ++ - Framework, das Windows, Mac OS X und Linux unterstützt und mit der nächsten Version 4.5 unter der LGPL veröffentlicht wird.

fhe
quelle
22
Beachten Sie, dass Ihre App saugt, wenn Sie Qt verwenden. Qt-basierte Apps sehen nicht wie native Mac-Apps aus und fühlen sich auch nicht so an. (Ein Beispiel finden Sie unter Google Earth.)
Peter Hosey
15
Peter: Das stimmt überhaupt nicht. Qt-basierte Apps können mit nativen Mac-Apps identisch aussehen und sich auch so anfühlen. Sie müssen lediglich plattformübergreifende Anpassungen vornehmen. Dies ist viel einfacher als das Schreiben einer nativen Benutzeroberfläche auf jeder Plattform.
Mike McQuaid
11
Mike, du bist falsch informiert. Neben anderen Mängeln verwenden Qt-basierte Apps auf dem Mac überhaupt nicht die nativen Steuerelemente, und die Qt-Bibliothek erstellt die gesamte Zeichnung selbst. Dies bedeutet, dass Qt-Apps keine Hardwarebeschleunigung für das 2D-Rendering erhalten, nicht mit Änderungen an der Benutzeroberfläche synchronisiert werden, die Apple an den Standardsteuerelementen vornimmt, und dass eine Qt-App keine ADA-Konformität oder Skriptfähigkeit liefern kann, wenn Sie diese nicht neu erfinden Räder selbst. Mit anderen Worten, versuchen Sie nicht, eine Qt-App auf dem Mac zu versenden. Google kann damit durchkommen: Sie können nicht.
NSResponder
13
Sie verwenden die nativen Steuerelemente, deshalb hat Qt eine Kakao- und Carbon-Version. Es gibt andere Probleme, aber viele Leute liefern Qt-Anwendungen auf dem Mac aus und sie funktionieren einwandfrei (und perfekt mit ein wenig Optimierung).
Mike McQuaid
2
Die Verwendung der nativen Steuerung bedeutet nicht, dass sie wie native Apps aussieht und sich anfühlt . Was ein natives Gefühl ausmacht, ist der Unterschied zwischen den einzelnen Betriebssystemen. Wenn Sie Ihre App so einstellen, dass sie auf einer bestimmten Plattform zu spüren ist, wird sie auf einer anderen Plattform nicht als nativ empfunden. Die Feinabstimmung kleiner Verhaltensweisen auf einer einmal abstrahierten Ebene ist immer schwieriger als auf einer nativen Ebene.
Eonil
9

Ja, du kannst sie mischen.

Sie müssen Objective-C verwenden, um Ihre GUI-Objekte direkt zu bearbeiten und Benachrichtigungen von ihnen zu erhalten.

Diese Objective-C-Objekte können die C ++ - Logik direkt aufrufen, wenn Sie sie in MM-Dateien anstelle der reinen Objective-C-MM-Dateien ablegen. Beachten Sie, dass Sie möglicherweise (viel) ältere Ratschläge sehen, die die Verwendung eines Großbuchstabens .M zur Angabe von Objective-C ++ vorschlagen. Dies ist jedoch sehr unzuverlässig und kann Sie und den Compiler wahrscheinlich verwirren.

Sie müssen nicht jedes C ++ - Objekt umbrechen, aber Ihr Objective-C-Code muss Zeiger darauf enthalten.

Apple veröffentlicht keine Beispiele mehr, die zeigen, wie das geht.

Es gibt ein großartiges Video von Peter Steinberger, das bei Realm [Objective] C ++ gehostet wird : Was könnte möglicherweise schief gehen? Ich kann es jedem empfehlen, der noch Objective-C ++ verwendet, und Sie können das Transkript schnell überfliegen.

Andy Dent
quelle
@SteveS Ihr Link ist auch kaputt
fferri
@fferi - Steinberger Link oben ist behoben. Die Carbon Cocoa Integration wurde ab 2007 von developer.apple.com von Apple entfernt. Dies zeigt an, dass Sie WIRKLICH keinen neuen Code mit Carbon APIs schreiben sollten. Zu diesem Zeitpunkt ist es sogar riskant, vorhandenen Code mithilfe von Carbon beizubehalten. Beziehen Sie sich auf die akzeptierte Antwort auf diese Frage oder auf diese, wenn Sie C ++ / Objective C mischen müssen, aber Carbon nicht verwenden sollten. Das heißt hier: Kohlenstoff-Kakao-Integration
SteveS
4

Wenn Sie nur Vanille C ++ verwenden möchten, wird dies absolut unterstützt und unterscheidet sich nicht von jeder anderen Plattform. Xcode hat sogar eine Vorlage unter Datei> Neues Projekt> Befehlszeilenprogramm> C ++ - Tool. Einige der beliebten Open-Source-Bibliotheken (libcurl, libxml2, sqlite usw.) werden mit OS X geliefert und stehen für die dynamische Verknüpfung zur Verfügung. Sie müssen keinen Kakao oder etwas Apple-spezifisches verwenden, wenn Sie nicht möchten.

Wenn Sie Cocoa in bestimmten Bereichen Ihrer App verwenden möchten, schauen Sie sich Objective-C ++ an . Sie können C ++ und Objective-C in derselben Datei mischen, indem Sie eine Erweiterung von .mm angeben oder mit der rechten Maustaste auf die Datei in Xcode klicken und Get Info> General auswählen und dann den Dateityp in sourcecode.cpp.objcpp ändern. Die zweite Option ist nützlich, wenn Sie eine CPP-Datei haben, in der Sie Objective-C in einem Mac-spezifischen #ifdef verwenden möchten.

Matt Stevens
quelle
1
Übrigens, die (wirklich nützliche) C ++ - Vorlage ist mit den neuesten Versionen von Xcode (4.x und 5.x) verschwunden
Jay
1

Obwohl dies eine jahrelange Frage ist ...

Ich habe versucht, einen C ++ - Wrapper für einige Cocoa-Klassen zu erstellen .

Es war eine ziemlich schöne Erfahrung. C ++ bot eine bessere Typensicherheit als Objective-C und brachte mich dazu, weniger Code zu schreiben. Die Kompilierungszeit und die Speichersicherheit sind jedoch schlechter. Es ist möglich, aber einige dynamikbasierte Funktionen waren nicht einfach zu handhaben. Ich denke, es macht keinen Sinn, sich unter C ++ damit zu befassen.

Auf jeden Fall wurde mein Projekt aufgrund der Ankündigung von Swift endgültig aufgegeben. Es löschte alle Gründe, warum ich zuerst C ++ verwenden wollte, und bietet noch mehr und bessere.

eonil
quelle
0

Wenn Sie eine rein grafische Anwendung schreiben, dh alles mit Code zeichnen, sollten Sie openFrameworks in Betracht ziehen . Es ist eine grafische OpenSource-Programmiersprache, die auf C / C ++ basiert. Es hat Addons, mit denen Leute die Sprache erweitern können. Sie haben ein Addon für das iPhone . Ich glaube, dass es mit der Bibliothek und den XCode-Projekten geliefert wird, mit denen Sie Apps für das iPhone und den iPod touch kompilieren können.

Meilen meow
quelle