4 Stimmen

Wie kann man eine C++-Bibliothek in Objective-C einbinden?

Ich habe eine C++-Bibliothek (.h nur), die die Implementierung einer Datenstruktur enthält, und ich würde sie gerne in meiner iPhone-App verwenden.

Zunächst habe ich einen Wrapper in Objective-C++ als Klasse geschrieben, die durch Komposition ein ivar der C++-Klasse hat. Dann musste ich 'gezwungen' sein, die Erweiterung der Wrapper-Klasse auf .mm zu ändern, und es schien in Ordnung zu sein. Aber dann muss ich diese gewickelte Klassendatei in mehrere andere Dateien einfügen, also muss ich auch ihre Erweiterung ändern (um eine Welle von Kompilierungsfehlern zu verhindern).

Habe ich recht? Gibt es einen Weg, die .mm-Erweiterung nur auf einige Dateien zu "beschränken"? (um so Namenskonflikte usw. zu verhindern)

EDIT: Einige weitere Informationen, die vielleicht helfen könnten: Ich benutze LLVM 1.5 als Compiler (ich habe bemerkt, dass die Anzahl der Kompilierungsfehler von GCC 4.2 zu LLVM 1.5 variiert, aber ich bin mir nicht sicher, ob das viel bedeutet, da ich sie nicht alle überprüft habe)

4voto

Barry Wark Punkte 106328

Meine Empfehlung ist, die C++-Bits in #ifdefs zu umschließen:

//MyWrapper.h

#ifdef __cplusplus
class ComposedClass;
#endif 

@interface MyWrapper : NSObject
{
#ifdef __cplusplus
ComposedClass *ptr;
#endif
}

// Hier werden die gewickelten Methoden platziert...
@end

Dies ist eine etwas einfache Version des PIMPL-Idioms, aber weniger Code und effektiv, um C++-Besonderheiten vor Ihrem reinen Objective-C-Code zu verbergen. Offensichtlich müssen Sie das Header von ComposedClass in Ihrem MyWrapper.mm inkludieren.

Wenn ComposedClass ein templatisierter Typ ist, müssen Sie den ersten Block anpassen zu

#ifdef __cplusplus
#include "ComposedClass.h"
#endif

anstatt einer Vorwärtsdeklaration zu verwenden und dann natürlich den templatisierten Typ in der Instanzvariablendeklaration Ihrer Objective-C-Klasse zu verwenden.

Dieser Ansatz wurde von Greg Parker, dem Laufzeitexperten bei Apple, vorgeschlagen.

0 Stimmen

Ich denke nicht, dass das eine gute Idee ist. Alle nicht-C++-Dateien, die diesen Header einbinden, "sehen" die geschützten Elemente nicht und haben daher unterschiedliche Größen für Klassen und verschiedene Versatzwerte für Instanzvariablen.

0 Stimmen

@Kristopher, mit dem modernen Objective-C-Laufzeit (die einzige Option auf iOS) sind Instanzvariablen nicht fragil, und das ist kein Problem.

0 Stimmen

@Barry Wark danke Barry, das scheint mir der einfachste Weg zu sein, aber anscheinend kann ich dies nicht erreichen, da ich Compile-Zeitfehler bekomme pastebin.com/tp9Zjhss es scheint, als ob ich etwas fehlt, ich dachte, es könnten Vorlagen sein, aber in deinem Link werden sie verwendet.

4voto

Ole Begemann Punkte 133946

Der gesamte Code, der einen C++-Codeausschnitt enthält (egal wie klein), muss mit Objective-C++ kompiliert werden (und daher in einer .mm-Datei sein). Wenn Sie die Anzahl der .mm-Dateien reduzieren möchten, müssten Sie die Funktionalität Ihres C++-Codes in einer Objective-C-Klasse einwickeln, so dass die öffentliche Schnittstelle dieser Klasse (d. h. ihre .h-Datei) nur aus Objective-C-Code besteht. Das bedeutet, die Wrapper-Klasse darf kein öffentliches ivar eines C++-Typs enthalten. Ob dies ein gangbarer Ansatz ist, wenn Ihre C++-Bibliothek nur aus einer Datenstruktur besteht, weiß ich nicht.

Beachten Sie, dass meines Wissens LLVM 1.5 noch keine C++-Unterstützung bietet (nur LLVM 2.0). Soweit mir bekannt ist, wenn Sie LLVM 1.5 auswählen, wechselt Xcode automatisch zu GCC für alle C++/Objective-C++-Dateien.

2voto

Omnifarious Punkte 52299

Ich bin mir nicht sicher, ob ich Ihre Frage vollständig verstehe, aber ich denke, die Antwort lautet "Ja".

Im Grunde genommen ist alles, was auf die Wrapper-Klasse verweisen muss, Objective-C++-Code und nicht nur C++.

Ich schlage vor, dass Sie die Verwendung der Wrapper-Klasse auf Implementierungsdateien (aka .cpp oder das Objective-C++-Äquivalent) beschränken. Sie sollten nicht dazu führen, dass die Headerdatei, die die implementierten Klassen beschreibt, zu Objective-C++ wird.

Techniken wie das Pimpl-Idiom können Benutzer Ihrer Klasse isolieren, damit sie nicht bemerken, dass sie teilweise in Objective-C++ implementiert ist.

0 Stimmen

+1 Ich habe verstanden, dass du die Kaskade begrenzt hast, indem du nur in den .mm-Dateien eingebunden hast.

0 Stimmen

@rano - Es sieht so aus, als wäre Ihr Problem das umgekehrte Problem dessen, zu dem ich die Lösung beschrieben habe. Und es scheint, dass Objective-C/C++ nicht das Konzept einer Implementierung getrennt von der Klassendefinition hat. Dies macht die Aufgabe viel schwieriger und erfordert ein größeres Verständnis als ich von Objective-C/C++ habe.

0 Stimmen

Ich verstehe jetzt nicht, was du meinst. Objective-C/C++ bietet eine Trennung für das Interface/Implementierung einer Klasse.

1voto

sb. Punkte 1120

Meine bevorzugte Lösung ist dieses Vorwärtsdeklarationsmakro:

#define FORWARD(cpp_class) struct cpp_class; typedef struct cpp_class cpp_class;

FORWARD(SomeCppClass);

@interface MyObjcWrapper : NSObject {
    SomeCppClass *ptr;
}

Dann ist es sicher, MyObjcWrapper.h in Objective-C und Objective-C++ Dateien einzuschließen.

Das stammt aus einem hilfreichen Blogpost, den ich vor ein paar Jahren gesehen habe - kann ihn jetzt leider nicht finden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X