2010-11-17 13 views
8

Sto cercando di creare un wrapper in Objective-C, quindi non devo scrivere C++ al di fuori delle classi della libreria.Creazione di un wrapper Objective-C per una libreria C++

Il file principale Library è LLAHProcessor.h .cpp

mio Wrapper è LLAHProcessorWrapper.h .mm

Si compila bene, ma quando aggiungo LLAHProcessorWrapper ad altra classe, (diciamo un UIView) come variabile membro ricevo centinaia di errori , come:

#include <map> : Map no such a file or directory 

e in ogni C++ classe/struttura:

Expected specifier-qualifier list before ClassName 

È come se il compilatore non riconoscesse il codice C++.

Mi chiedo cosa mi manca qui. Dev'essere qualcosa con il fatto che l'ho aggiunto a Xcode Target Properties:?

Other Link Flags : -lstdc++ -lz 

O forse ho bisogno di aggiungere nuove bandiere qui?

Grazie in anticipo

+1

È fondamentale che 'LLAHProcessorWrapper.h' non contenga alcun codice C++. 'LLAHProcessor.h' dovrebbe essere importato nel tuo' .mm'. file, non nel file '.h'. Sei stato tu? –

+0

Hai anche file .m nel progetto? –

+0

@Chris Ho molti file .m. Questo è un bel programma. – nacho4d

risposta

6

Il tuo problema è che i file .m sono compilati come C anziché C++. Pertanto, quando il compilatore incontra qualsiasi C++ anche in un file di intestazione durante la compilazione di un file .m, lo farà.

Senza dubbio è necessario inserire del C++ nel file di intestazione perché l'oggetto Objective C racchiude un oggetto C++, ma ci sono modi per aggirare questo problema. Un modo sarebbe utilizzare un puntatore all'oggetto C++ e utilizzare il pratico preprocessore definendo __cplusplus definito per C++ (e Objective-C++) ma non per C (o Objective-C), ad es.

// LLAHProcessorWrapper.h 

#if defined __cplusplus 
class MyCPPClass; // forward class declaration 
#else 
typedef struct MyCPPClass MyCPPClass; // forward struct declaration 
#endif 

@interface MyOCClass : NSObject 
{ 
@private 
    MyCPPClass* cppObject; 
} 

// methods and properties 

@end 

Dal momento che non hai mai dereferenziare i membri del cppObject al di fuori del file .mm non importa che non hai mai fornito una definizione completa per la struct.

Si dovrebbe new e delete il puntatore rispettivamente in -init e -dealloc. Includere la dichiarazione completa della classe C++ in LLAHProcessorWrapper.mm.

+1

In questo caso è utile a chiunque: mi sono fatto notare avendo ancora '#include" MyCPPClass.h "' nel 'LLAHProcessorWrapper.h'. Dovrebbe essere nel 'LLAHProcessorWrapper.mm' invece. – Ross

+0

Suppongo che ora possiamo usare anche le estensioni di classe? forse un approccio migliore? – Ahmed

4

Tutto quello che devi fare è quello di creare un .mm come avete fatto, e il compilatore dovrebbe prendere cura di tutto.

L'avvertenza è che non è sicuro avere qualcosa di C++ correlato nei file .h, dal momento che possono/saranno importati da altri file solo Objective-C, quindi tutto si interromperà. Il problema principale qui è che non è possibile definire i tipi C++ direttamente come variabili di istanza per la classe wrapper Objective-C, a meno che ogni singolo file .m sia rinominato come file Objective-C++ .mm.

La soluzione è definire le variabili di istanza come void* nel file di intestazione e accedervi con il cast di tipo dal file di implementazione. La soluzione più semplice per questo sarebbe accedere alla variabile di istanza usando una proprietà privata che è stata tipizzata per te.

classe codice

Esempio assumendo Foo è un C++ definito Foo.h:

// FooWrapper.h 
#import <Foundation/Foundation.h> 

@interface FooWrapper : NSObject { 
@private 
    void* foo; 
} 
// Actual wrapper API for Foo… 
@end 


// FooWrapper.mm 
#import "FooWrapper.h" 
#include <map> 
#include "Foo.h" 

@interface FooWrapper() 
@property(nonatomic, assign) Foo* foo; 
@end 

@implementation FooWrapper 
-(Foo*)foo { 
    return (Foo*)foo; 
} 
-(void)setFoo:(Foo*)aFoo { 
    foo = (void*)aFoo; 
} 
// Implementation of actual API for Foo… 
@end 
0

In ogni file di intestazione (.h) in cui si desidera fare riferimento a LLAHProcessorWrapper, uso in avanti definizioni di classe, invece di importazioni, in questo modo:

@class LLAHProcessorWrapper; 
@interface SomeView : UIView { 
    LLAHProcessorWrapper *wrapper; 
} 

e assicurarsi che il file di implementazione corrispondente ha #include LLAHProcessorWrapper.h o #import LLAHProcessorWrapper.h.

Qualsiasi file di implementazione in cui si #include o #import l'intestazione deve avere .mm come suo suffisso se LLAHProcessorWrapper.h o qualsiasi altra cosa in tutto l'albero includono ha alcuna sintassi C++ a tutti. In questo modo, avere un file .mm ha la tendenza a significare che enormi porzioni di un codebase devono avere i loro file rinominati in .mm.

Problemi correlati