Objective-C et C++

fouffouf Membre
01:05 modifié dans API AppKit #1
Bonjour.

Dans l'application sur laquelle je travaille, j'utilise des classes C++ qui seront appelées par des objets en Obj-C. Je sais bien que pour utiliser du C++ dans du code Obj-C, il suffit de "passer" en Objective-C++ en modifiant le nom du fichier (extension .mm au lieu de .m).

Le point critique est que je n'ai absolument aucune envie de passer tout les fichiers d'implémentation de mon projet ou presque en .mm. Ne peut on pas se limiter à  certains fichier.

Pour être tout à  fait clair, j'ai une fonction qui ne prends en argument absolument aucun objet ni en Obj-C ni en C++ mais qui en utilise dans son implémentation. Je déclare alors dans le header associé cette fonction, puis je fais appel à  cette fonction dans le fichier .m . Le problème est alors que le linker m'engueule un tout petit peu et me dit qu'il ne trouve pas le symbole associé à  la fonction en question. Je change alors le nom du fichier en .m et ca marche alors très très bien.
Ne puis-je pas garder d'une manière ou d'une autre le fichier en Obj-C et non en Obj-C++ ?

Réponses

  • AliGatorAliGator Membre, Modérateur
    01:05 modifié #2
    J'ai jamais fait ça dans le cadre de l'Objective-C, ceci dit je pense que tu vas peut-être devoir jouer avec la directive [tt]extern "C"[/tt].

    En effet le problème est qu'à  la compilation de ton fichier de code en fichier objet, les noms des fonctions sont transformés en symboles (name mangling), et :
    - autant en C ce mangling n'utilise que le nom de la fonction et le nombre d'octets pris par ses arguments grosso modo (je me rappelle plus es détails mais bon)
    - autant en C++ comme on peut surcharger une méthode (avoir une méthode qui a le même nom qu'une autre mais des arguments différents) ou faire de l'encapsulation (et permettre à  2 méthodes de même nom de coexister si elles sont dans deux classes différentes), le name mangling a été adapté en conséquence et n'est donc pas le même qu'en C.

    C'est pour ça que quand on souhaite linker entre eux plusieurs fichiers objets (plusieurs fichiers C et C++ chacun compilés de leur côté), pour pouvoir appeler des méthodes de l'un depuis l'autre, il faut cette petite information/directive de [tt]extern "C"[/tt].

    A creuser donc.
  • fouffouf Membre
    01:05 modifié #3
    J'ai trouver un truc, mais ca ne me plait pas du tout :

    Je crée une classe DBToto qui a une méthode de classe +totoFaitTonTruc: qui fait appel directement à  la fonction totoFaitSonTruc(). Là , tout se passe très bien, mais faire une classe uniquement pour ca je trouve que c'est mal parce que les classes ne sont pas faites pour cela (ce sont les fonctions qui sont chargées de ce type de travail).

    Je connais le truc du "extern C" (même si je n'en connaissais pas l'origine, je me coucherais moins bête se soir ... ) et le name mangling permet d'expliquer en détail le message d'erreur que je recevais ("symbol _nomDeLaFonction not found" et non nomDeLaFonction, le name mangling doit rajouter un _). Merci beaucoup AliGator
  • AliGatorAliGator Membre, Modérateur
    01:05 modifié #4
    J'ai pas l'impression qu'il y ait directement la réponse, mais y'a de quoi lire quand même dans la doc ici, ça peut p'tet aider.

    En tout cas, pour moi faut au moins essayer le extern C :
    #ifdef __cplusplus<br />extern &quot;C&quot; {<br />#endif<br /><br />... code<br /><br />#ifdef __cplusplus<br />} // extern &quot;C&quot;<br />#endif
    
  • yoannyoann Membre
    01:05 modifié #5
    Pour avoir déjà  joué avec l'Objective-C et le C++ en même temps, soit tu fait que des .mm soit tun fait une classe wrapper en ObjC de ta classe C++

    C'est du moins les deux méthodes les plus "pratique" que j'utilise
  • psychoh13psychoh13 Mothership Developer Membre
    01:05 modifié #6
    Je crois qu'il veut éviter le wrapper justement.

    Pour les fonctions tu peux soit encadrer toutes tes déclarations avec ce qu'indique aligator, c'est-à -dire extern "C" { }, soit tu peux aussi déclarer les fonctions comme extern "C" une à  une. La technique généralement choisie est celle-ci:

    Tu mets ça dans ton pch par exemple, ou dans un header que tu importes dans chaque fichier.
    #ifdef __cplusplus<br />#define MY_EXTERN extern &quot;C&quot;<br />#else<br />#define MY_EXTERN extern<br />#endif
    


    puis tu l'utilises comme suit:

    // Fonction utilisée aussi bien en C qu&#39;en C++<br />MY_EXTERN int function(void);<br /><br />// Variable globale ausis bien utilisée en C qu&#39;en C++<br />MY_EXTERN NSString *const MyDictionaryKey;<br />
    


    Et pour les ivars qui vont être des objets C++ sous le capot, tu peux utiliser void* avec allocation dynamique, ainsi qu'une macro dans le code C++ pour faire un cast faire le vrai type de ta variable en C++.

    Exemple:
    // MyClass.h :<br />@interface MyClass : NSObject<br />{<br />@private<br />    void *_reserved;<br />}<br />@end<br /><br />// MyClass.mm<br /><br />#define ITEMS ((std::vector&lt;int&gt;*)_reserved)<br />@implementation MyClass<br />- (id)init<br />{<br />    if(self = [super init])<br />    {<br />        _reserved = new std::vector&lt;int&gt;();<br />        ITEMS-&gt;push_back(0);<br />    }<br />    return self;<br />}<br />@end
    

Connectez-vous ou Inscrivez-vous pour répondre.