Question

J'utilise une bibliothèque tierce qui a une déclaration comme celle-ci:

typedef struct {} __INTERNAL_DATA, *HandleType;

Et j'aimerais créer une classe prenant un HandleType dans le constructeur:

class Foo
{
    Foo(HandleType h);
}

sans , y compris l'en-tête qui définit HandleType . Normalement, je dirais simplement un tel type, mais je ne peux pas comprendre la syntaxe. Je veux vraiment dire quelque chose comme:

struct *HandleType;

Mais cela dit "Identifiant attendu avant *" dans GCC. La seule solution que je puisse voir est d’écrire ma classe comme ceci:

struct __INTERNAL_DATA;
class Foo
{
    Foo(__INTERNAL_DATA *h);
}

Mais cela dépend des détails internes de la bibliothèque. C’est-à-dire qu’elle utilise le nom __INTERNAL_DATA, qui est un détail de la mise en oeuvre.

Il semble qu'il devrait être possible de déclarer / déclarer HandleType (une partie de l'API publique) sans utiliser __INTERNAL_DATA (une partie de l'implémentation de la bibliothèque.) Quelqu'un sait comment?

EDIT: ajout de plus de détails sur ce que je recherche.

Était-ce utile?

La solution

Mise à jour:

  

Je l'utilise dans l'implémentation .cpp de Foo, mais je veux éviter de l'inclure dans mon en-tête .h pour Foo. Peut-être que je suis juste trop pédant? :)

Oui, vous l'êtes :) Allez-y avec la déclaration anticipée.

Si HandleType fait partie de l'interface, il doit y avoir un en-tête le déclarant. Utilisez cet en-tête.

Votre problème est encore vague. Vous essayez de vous protéger contre quelque chose que vous ne pouvez pas.

Vous pouvez ajouter la ligne suivante à votre bibliothèque client:

typedef struct INTERNAL_DATA *HandleType;

mais, si le nom / la structure change, vous risquez de vous faire prendre au piège.

Essayez les modèles:

template <class T>
class Foo
{
    Foo(T h);
};

La déclaration en aval va bien. Si vous allez utiliser des pointeurs ou des références, vous n'avez besoin que d'une déclaration de classe ( __ INTERNAL_DATA ). Toutefois, si vous souhaitez utiliser une fonction membre ou un objet, vous devez inclure l'en-tête.

Autres conseils

Si le type est dans une bibliothèque tierce, le gros avantage de la déclaration en aval (isoler les reconstructions en raison de modifications des en-têtes) est effectivement perdu.

Si les délais de compilation vous préoccupent (il s'agit d'un en-tête important), vous pouvez peut-être le placer dans un en-tête précompilé ou simplement inclure l'en-tête correspondant dans une bibliothèque.

E.g. de nombreux en-têtes de bibliothèque ressemblent à

// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"
 typedef struct {} __INTERNAL_DATA, *HandleType;

Si elle est définie ainsi (sur une seule ligne), alors __INTERNAL DATA fait partie de l'interface publique autant que HandleType.

Cependant, je ne pense pas que __ INTERNAL_DATA existe réellement. Plus que probablement, HandleType est vraiment (en interne) un int. Cette définition étrange est juste un moyen de la définir de sorte qu'elle ait la même taille qu'un int, mais distincte, de sorte que le compilateur vous envoie une erreur si vous essayez de passer un int où vous êtes censé passer un HandleType. Le fournisseur de la bibliothèque aurait tout aussi bien pu le définir comme "int". ou "void *", mais de cette façon nous obtenons une vérification de type.

Par conséquent, __ INTERNAL_DATA est simplement une convention et ne changera pas.

UPDATE: Ce qui précède était un peu comme un cauchemar mental ... OK, __ INTERNAL_DATA n'existe définitivement pas. Nous le savons bien, car nous pouvons voir sa définition comme une structure vide. Je vais deviner que la bibliothèque tierce utilise "C". lien externe (pas de gestion de nom), auquel cas, copiez simplement le typedef - tout ira bien.

Dans la bibliothèque elle-même, HandleType aura une définition complètement différente; peut-être int , peut-être "struct MyStruct {.......} *".

Si vous ne voulez vraiment pas vraiment exposer _INTERNAL_DATA à l'appelant, votre seul choix est d'utiliser typedef void * HandleType ; Ensuite, dans votre bibliothèque, vous pouvez faire tout ce que vous voulez, y compris changer l’implémentation complète de * HandleType.

Créez simplement une fonction d'assistance pour accéder à vos données réelles.

inline _INTERNAL_DATA* Impl(HandleType h) {
    return static_cast<_INTERNAL_DATA*>(h);
}

Je ne sais pas trop ce que vous allez faire, mais ce qui suit fonctionnera sans inclure le fichier d'en-tête:

// foo.h
class Foo
{
    public:
    template<typename T>Foo(T* h) { /* body of constructor */ }
};

Attention, vous devrez toujours avoir accès aux membres publics de __ INTERNAL_DATA dans le corps du constructeur.

edit: comme l'a souligné James Curran, la structure __ INTERNAL_DATA n'a pas de membre et peut donc être utilisée, comme ci-dessus, sans problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top