2010-11-17 10 views
8

Je tente de créer un wrapper en Objective-C, donc je n'ai pas besoin d'écrire C++ en dehors des classes de la bibliothèque.Création d'un wrapper Objective-C pour une bibliothèque C++

Le fichier principal bibliothèque est LLAHProcessor.h .cpp

Mon Wrapper est LLAHProcessorWrapper.h .mm

Il compile très bien, mais quand j'ajoute LLAHProcessorWrapper à d'autres classes, (permet de dire un UIView) en tant que variable membre, je reçois des centaines d'erreurs , comme:

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

et dans toutes les classes C++/struct:

Expected specifier-qualifier list before ClassName 

Est comme le compilateur ne reconnaît pas le code C++.

Je me demande ce qui me manque ici. Cela doit-il être quelque chose avec le fait que j'ai ajouté ceci à Xcode Target Properties:?

Other Link Flags : -lstdc++ -lz 

Ou peut-être que j'ai besoin d'ajouter de nouveaux drapeaux ici?

Merci à l'avance

+1

Il est essentiel que 'LLAHProcessorWrapper.h' ne contienne aucun code C++. 'LLAHProcessor.h' devrait être importé dans votre' .mm'. fichier, pas dans le fichier '.h'. As-tu fais ça? –

+0

Vous avez également des fichiers .m dans le projet? –

+0

@Chris J'ai beaucoup de fichiers .m. C'est un programme assez important. – nacho4d

Répondre

6

Votre problème est que les fichiers .m sont compilés en C au lieu de C++. Ainsi, lorsque le compilateur rencontre un C++ même dans un fichier d'en-tête lors de la compilation d'un fichier .m, il va barf. Sans aucun doute, vous devez mettre du C++ dans votre fichier d'en-tête parce que votre objet Objective C encapsule un objet C++, mais il existe des moyens de contourner ce problème. Une façon serait d'utiliser un pointeur vers l'objet C++ et d'utiliser le préprocesseur pratique, définissez __cplusplus qui est défini pour C++ (et Objective-C++) mais pas pour C (ou Objective-C), par ex.

// 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 

Puisque vous ne déréférencer les membres du cppObject en dehors du fichier .mm il ne fournit pas d'importance que vous ne une définition complète de la struct.

Vous souhaitez new et delete respectivement le pointeur dans -init et -dealloc. Vous devez inclure la déclaration de classe C++ complète dans LLAHProcessorWrapper.mm.

+1

Incase cela est utile à tout le monde: je me suis fait attraper en ayant toujours '#include" MyCPPClass.h "' dans le 'LLAHProcessorWrapper.h'. Il devrait être dans le 'LLAHProcessorWrapper.mm' à la place. – Ross

+0

Je suppose que nous pouvons maintenant utiliser des extensions de classe aussi? peut-être une meilleure approche? – Ahmed

4

Tout ce que vous devez faire est de créer une .mm que vous avez fait, et le compilateur doit prendre soin de tout. L'inconvénient étant qu'il n'est pas sûr d'avoir quelque chose de C++ lié dans les fichiers .h, car ils peuvent/seront importés par d'autres fichiers seulement Objective-C, puis tout se décompose. Le problème principal ici est que vous ne pouvez pas définir les types C++ directement comme variables d'instance pour votre classe wrapper Objective-C, sauf si chaque fichier .m est renommé en tant que fichier Objective-C++ .mm.

La solution consiste à définir les variables d'instance sous la forme void* dans le fichier d'en-tête et à y accéder avec cast de type à partir du fichier d'implémentation. La solution la plus simple pour cela serait d'accéder à la variable d'instance en utilisant une propriété privée qui correspond à la catégorie.

code exemple en supposant Foo est une classe C++ définie dans 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

Dans un fichier en-tête (.h) dans lequel vous voulez faire référence à LLAHProcessorWrapper, utiliser des définitions de classe avant au lieu des importations, comme suit:

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

et assurez-vous que le fichier de mise en œuvre correspondant a #include LLAHProcessorWrapper.h ou #import LLAHProcessorWrapper.h.

Tout fichier de mise en œuvre dans lequel vous #include ou #import votre tête doit avoir .mm comme suffixe si LLAHProcessorWrapper.h ou toute autre chose dans l'ensemble de l'arbre comprennent a une syntaxe C++ du tout. De cette façon, avoir un fichier .mm a tendance à signifier que d'énormes portions d'une base de code doivent avoir leurs fichiers renommés en .mm.