2010-02-09 9 views
6

Ich habe eine kleine C++ - Anwendung, die ich Objective-C-Klassen importiert. Es funktioniert als Objective-C++ - Dateien, .mm, aber jede C++ - Datei, die eine Kopfzeile enthält, die eventuell einen Objective-C-Header enthält, muss in eine .mm-Erweiterung für die richtigen GCC-Treiber umbenannt werden.Kann ich die C++ - Hauptfunktion und -Klassen von Objective-C- und/oder C-Routinen beim Kompilieren und Verknüpfen trennen?

Gibt es eine Möglichkeit, entweder einen reinen C++ - Wrapper für Objective-C-Klassen zu schreiben, oder kann ich die Objective-C-Objekte irgendwie trennen und nur separat verknüpfen? Vielleicht könnte ich, selbst wenn die Objective-C-Klassen eine kleine Bibliothek werden würden, zur Kompilierungszeit statisch neu verknüpfen?

Das Problem ist, dass dieser Code plattformübergreifend ist, und es ist schwieriger, auf Systemen zu kompilieren, die normalerweise Objective-C nicht verwenden (d. H. Nicht Macs). Obwohl Präprozessorbefehle jede Implementierung von Objective-C-Code unter Windows oder Linux einschränken, hat der ursprüngliche Code immer noch die Erweiterung .mm und GCC behandelt den Code weiterhin als Objective-C++.

Antwort

3

Normalerweise wickeln Sie einfach Ihre Objective-C-Klassen mit C++ - Klassen z. Verwenden von opaque pointers und Weiterleiten von Aufrufen an C++ - Methoden an Objective-C-Methoden.

Auf diese Weise müssen Ihre portablen C++ - Quellen keine Objective-C-Includes sehen, und Sie müssen im Idealfall nur die Implementierungsdateien für die Wrapper auf verschiedenen Plattformen austauschen.

Beispiel:

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

// ... 
+0

also würde struct Wrapper :: Opaque 'OBJCClass * name = [[OBJCClass alloc] init]' und Wrapper :: f() würde [Name f] aufrufen, wenn es so verknüpft war? –

+0

Ja, Sie könnten die enthaltene Objective-C-Klasse im Wrapper- oder Opaque-Konstruktor zuweisen und initialisieren, was auch immer Ihnen passt, und die C++ - Klassenmethoden würden die Aufrufe an Ihre Objective-C-Klasse weiterleiten. –

2

Ja, das ist ohne weiteres möglich, in beide Richtungen, wenn Sie wissen, ein paar Tricks:

1) Die "id" Typ wird in einem einfachen C-Header tatsächlich definiert. So können Sie folgendes tun:

In der Kopfzeile:

#include <objc/objc.h> 

class MyWindow 
{ 
public: 
    MyWindow(); 
    ~MyWindow(); 
protected: 
    id  mCocoaWindow; 
}; 

in Ihrer Implementierung (.mm):

#include "MyWindow.h" 
#include <Cocoa/Cocoa.h> 

MyWindow::MyWindow() 
{ 
    mCocoaWindow = [[NSWindow alloc] init]; 
} 

MyWindow::~MyWindow() 
{ 
    [mCocoaWindow release]; 
    mCocoaWindow = nil; 
} 

2) Es gibt zwei Präprozessorkonstanten Sie ausschließen C verwenden können ++/ObjC spezifischen Code, wenn eine Quelldatei sie beinhaltet, dass eines der beiden, aber nicht ObjC++:

#if __OBJC__ 
// ObjC code goes here. 
#endif /* __OBJC__*/ 

#if __cplusplus 
// C++ code goes here. 
#endif 

Sei vorsichtig, du kannst nicht einfach Ivars oder virtuelle Methoden mit einem #ifdef hinzufügen/entfernen, das zwei Klassen mit unterschiedlichen Speicherlayouts erstellt und deine App auf sehr seltsame Weise zum Absturz bringt.

3) Sie können einen Zeiger auf eine Struktur verwenden, ohne den Inhalt zu erklären:

In der Kopfzeile:

@interface MyCppObjectWrapper : NSObject 
{ 
    struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++. 
} 

@end 

in Ihrer Implementierung-Datei (.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 

Dies macht Ihren Header zu einem einfachen Standard C oder ObjC, während Ihre Implementierungsdatei Konstruktoren/Destruktoren aller aufgerufenen Ivars aufruft, ohne dass Sie jedes als Objekt auf dem He erstellen/löschen müssen ap.

Dies ist alles nur die Mac-Seite der Dinge, aber das würde bedeuten, dass Sie die ObjC-Sachen aus Ihren Headern behalten oder zumindest kompilieren könnten, wenn sie von plattformübergreifenden Client-Dateien der Mac-Implementierung Ihres verwendet werden C++ Portabilitätsebene.

Verwandte Themen