6 votes

Puis-je séparer la fonction principale C++ et les classes des routines Objective-C et/ou C lors de la compilation et de la liaison?

J'ai une petite application C++ où j'ai importé des classes Objective-C. Ça fonctionne avec des fichiers Objective-C++, .mm, mais tout fichier C++ qui inclut un en-tête qui pourrait finir par inclure un en-tête Objective-C doit être renommé avec une extension .mm pour les bons pilotes GCC.

Y a-t-il un moyen d'écrire un enveloppe purement C++ pour les classes Objective-C ou puis-je séparer les objets Objective-C d'une manière ou d'une autre et les lier séparément ? Peut-être même si les classes Objective-C devenaient une petite bibliothèque que je pourrais relier statiquement au moment de la compilation ?

Le problème est que ce code est multiplateforme et il est plus difficile à compiler sur des systèmes qui n'utilisent normalement pas Objective-C (c'est-à-dire pas les Macs). Même si des commandes de préprocesseur restreignent toute implémentation de code Objective-C sur Windows ou Linux, le code original a toujours des extensions .mm et GCC traite toujours le code comme de l'Objective-C++.

3voto

Georg Fritzsche Points 59185

Généralement, vous enveloppez simplement vos classes Objective-C avec des classes C++ en utilisant par exemple des pointeurs opaques et en redirigeant les appels aux méthodes C++ vers les méthodes Objective-C.

Ainsi, vos sources C++ portables n'ont jamais à voir les inclusions Objective-C et idéalement, vous n'avez qu'à changer les fichiers d'implémentation des wrappers sur différentes plateformes.

Exemple:

// header c++ :
class Wrapper {
    struct Opaque;
    Opaque* opaque;
    // ...
public:
    void f();
};

// Source Objective-C++ sur Mac:
struct Wrapper::Opaque {
    id contained;
    // ...
};

void Wrapper::f() {
    [opaque->contained f];
}

// ...

3voto

uliwitness Points 2085

Oui, c'est facilement possible, dans les deux sens, si vous connaissez quelques astuces :

1) Le type "id" est en fait défini dans un en-tête C standard. Vous pouvez donc faire ce qui suit:

Dans votre en-tête :

#include 

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

Dans votre implémentation (.mm) :

#include "MyWindow.h"
#include 

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

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

2) Il y a deux constantes de préprocesseur que vous pouvez utiliser pour exclure le code spécifique à C++/ObjC lorsqu'un fichier source les inclut, qui est l'une des deux, mais pas ObjC++ :

#if __OBJC__
// Le code ObjC va ici.
#endif /* __OBJC__*/

#if __cplusplus
// Le code C++ va ici.
#endif

Faites juste attention, vous ne pouvez pas simplement ajouter/supprimer des ivars ou des méthodes virtuelles avec un #ifdef, cela créera deux classes avec des mises en mémoire différentes et fera planter votre application de façon très étrange.

3) Vous pouvez utiliser un pointeur vers une structure sans déclarer son contenu :

Dans votre en-tête :

@interface MyCppObjectWrapper : NSObject
{
    struct MyCppObjectWrapperIVars    *ivars;    // C'est directement ObjC, pas de ++.
}

@end

Dans votre fichier d'implémentation (.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

Ceci rendra votre en-tête simple en C standard ou ObjC, tandis que votre fichier d'implémentation appelle les constructeurs/destructeurs de tous les ivars sans que vous ayez à créer/supprimer chacun en tant qu'objet sur le tas.

Tout cela concerne uniquement le côté Mac, mais cela signifierait que vous pourriez garder les éléments ObjC hors de vos en-têtes, ou du moins les rendre compilables lorsqu'ils sont utilisés à partir de fichiers clients multiplateformes de l'implémentation Mac de votre couche de portabilité C++.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X