2009-06-29 6 views
5

Je dois mélanger Objective-C et C++. Je voudrais cacher tous les trucs C++ dans une classe et garder tous les autres objectifs Objective-C. Le problème est que je veux avoir des classes C++ comme variables d'instance. Cela signifie qu'ils doivent être mentionnés dans le fichier d'en-tête, qui est inclus par d'autres classes et que C++ commence à s'étendre à l'ensemble de l'application. La meilleure solution que j'ai pu utiliser jusqu'à présent ressemble à ceci:Classes C++ comme variables d'instance d'une classe Objective-C

#ifdef __cplusplus 
#import "cppheader.h" 
#endif 

@interface Foo : NSObject 
{ 
    id regularObjectiveCProperty; 
    #ifdef __cplusplus 
    CPPClass cppStuff; 
    #endif 
} 

@end 

Cela fonctionne. Le fichier d'implémentation a une extension mm, de sorte qu'il est compilé en Objective-C mélangé avec C++, le #ifdef déverrouille le contenu C++ et nous y voilà. Quand une autre classe purement Objective-C importe l'en-tête, le contenu C++ est caché et la classe ne voit rien de spécial. Cela ressemble à un hack, y a-t-il une meilleure solution?

+1

Il est fondamentalement ce que je suis venu avec quand j'eu le même problème. Mais faites attention à votre ifdef: vous devez insérer un padding pour la branche non-cpp. Sinon, le compilateur ne connaitrait pas la taille de vos objets Foo. Bien que cela ne vienne pas perturber les builds var d'instance non fragiles, c'est définitivement un problème pour les anciennes cibles de style. –

+0

J'ai copié l'approche que vous avez décrite ci-dessus. Semblait assez agréable et facile, mais alors il a causé quelques problèmes de corruption de mémoire fou: http://stackoverflow.com/questions/2458652/objective-c-insanity-simple-assignement-to-a-single-float-variable-results – morgancodes

Répondre

8

Cela ressemble à une utilisation classique pour un protocole interface/@. Définissez un protocole objectif-c pour l'API puis fournissez une implémentation de ce protocole en utilisant votre classe Objective-C++. De cette façon, les clients doivent seulement connaître le protocole et non l'en-tête de l'implémentation. Ainsi, compte tenu de la mise en œuvre originale

@interface Foo : NSObject 
{ 
    id regularObjectiveCProperty; 
    CPPClass cppStuff; 

} 

@end 

Je définirais un protocole

//Extending the NSObject protocol gives the NSObject 
// protocol methods. If not all implementations are 
// descended from NSObject, skip this. 
@protocol IFoo <NSObject> 

// Foo methods here 
@end 

et modifier la déclaration Foo originale

@interface Foo : NSObject <IFoo> 
{ 
    id regularObjectiveCProperty; 
    CPPClass cppStuff; 
} 

@end 

code client peut alors travailler avec le type id<IFoo> et n'a pas besoin être compilé en Objective-C++. Évidemment, vous pouvez passer une instance de Foo à ces clients.

+0

Si l'@faceface Foo est dans le fichier .h, est-ce possible d'empêcher l'influence d'obj-C++? Si le fichier @interface Foo est dans un fichier .mm, comment puis-je en faire une instance? – Eonil

+1

Tout module qui importe Foo.h devra être compilé en Objective-C++, mais le code client doit importer * seulement * l'en-tête d'IFoo pour utiliser IFoo et ne peut donc être que Objective-C. C'est un modèle de gestion de dépendance classique. –

+0

Dans votre exemple, comment instancier un nouveau Foo sans importer l'en-tête? La première chose qui me vient à l'esprit est une classe de fabrique Objective C++ qui n'importera pas de contenu C++ dans son en-tête. Tout cela semble très compliqué. Il y a aussi cette approche: http://stackoverflow.com/questions/2262011/adding-c-object-to-objective-c-class/2262395 mais je ne l'ai pas fait fonctionner (voir http://stackoverflow.com/questions/2463970/trouble-using-opaque-pointeurs-dans-objectif-c) – morgancodes

1

Y at-il une raison particulière pour laquelle vous ne pouvez pas simplement utiliser Objective C++ pour tout? Il suffit de basculer le compilateur vers Compile Sources As: Objective C++ (ou renommer tous vos fichiers sources de .cpp ou .m en .mm). Ensuite, vous pouvez librement Intermix votre C++ et Objective C.

C++ commence à se propager à l'ensemble de l'application

Quel problème est là avec ça? Si votre code Objective C ne fait que du code C/Objective C en général, il ne sera certainement pas affecté du tout en étant compilé en C++. Il n'y a pas de problèmes de performance en termes de taille ou de vitesse.

Les deux seuls inconvénients que j'ai trouvés sont: vous ne pouvez pas (encore) utiliser l'analyseur statique clang à l'analyseC++; certains codes C (relativement étranges) ne fonctionneront pas en C++, ce qui est parfois un problème lors de l'utilisation de code C tiers.

+0

Le seul problème est que je ne suis pas à l'aise avec C++ et j'avais peur qu'il y ait quelques différences subtiles pourrait conduire à des bugs. J'aime l'idée que C++ ne soit encapsulé que dans la classe qui en a vraiment besoin. Mais merci, c'est certainement une solution. – zoul

0

Vous pourriez trouver que vous avez des problèmes à le faire - d'après ce que je me souviens de ObjectiveC++, vous pouvez trouver que le constructeur et le destructeur pour votre objet C++ inclus ne seront pas appelés.

3

J'ai également rencontré ce problème récemment. Dans mon cas, un protocole était exagéré. Je devais juste garder un pointeur vers un objet d'accès aux données qui se trouvait être un objet C++. Ce que j'ai fait a été de déclarer la classe avec une variable d'instance void * et de la lancer quand je l'utilise dans les méthodes d'instance.

Il s'agit d'un petit bidouillage, mais conceptuellement, c'est très similaire à ce qu'est le type Objective-C id.

0

NE LE FAITES PAS

Si vous IFDEF à une variable d'instance, qui donnera deux instances distinctes dispositions variables pour cette classe. Vous obtiendrez des smashers de mémoire aléatoires partout parce que la mémoire allouée à l'objet dans la moitié des cas sera trop courte. Au lieu de ifdefing la variable d'instance, en avant-déclarer son type comme

struct CPPClass; 

et un pointeur dans la Ivar, puis dans votre init/dealloc méthodes appellent nouvelle/supprimer pour créer l'objet. Si vous avez plusieurs objets, vous pouvez créer une structure pour contenir tous les ivars C++ directement, puis simplement créer/supprimer cette structure.

Voir ce fil pour plus de détails et d'autres liens vers des informations, y compris un podcast qui parle longuement de ObjC++: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

+0

En C, un type struct devrait être appelé 'struct CPPClass', pas' CPPClass', donc ils devraient aussi changer cela. – newacct

+0

Dans la déclaration ivar, oui, bonne prise. Pour C++ struct Foo et Foo sont les mêmes, donc c'est seulement nécessaire dans l'en-tête. Habituellement, j'écris juste struct devant le nom de la classe partout où je l'utilise, vous n'avez pas besoin d'une déclaration de structure séparée comme je l'ai mentionné ici seul. – uliwitness

Questions connexes