Domanda

Sto usando una libreria di terze parti che ha una dichiarazione come questa:

typedef struct {} __INTERNAL_DATA, *HandleType;

E vorrei creare una classe che accetta un HandleType nel costruttore:

class Foo
{
    Foo(HandleType h);
}

senza incluso l'intestazione che definisce HandleType . Normalmente, dichiarerei semplicemente un tale tipo, ma non riesco a capire la sintassi per questo. Voglio davvero dire qualcosa del tipo:

struct *HandleType;

Ma questo dice " Identificatore previsto prima di * " nel GCC. L'unica soluzione che posso vedere è scrivere la mia classe in questo modo:

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

Ma questo si basa sui dettagli interni della libreria. Vale a dire, utilizza il nome __INTERNAL_DATA, che è un dettaglio di implementazione.

Sembra che dovrebbe essere possibile inoltrare HandleType (parte dell'API pubblica) senza utilizzare __INTERNAL_DATA (parte dell'implementazione della libreria.) Qualcuno sa come?

EDIT: aggiunti ulteriori dettagli su ciò che sto cercando.

È stato utile?

Soluzione

Aggiornamento:

  

Lo sto usando nell'implementazione .cpp di Foo, ma voglio evitare di includerlo nella mia intestazione .h per Foo. Forse sono solo troppo pedante? :)

Sì, sì :) Procedi con la dichiarazione in avanti.

Se HandleType fa parte dell'interfaccia, deve essere presente un'intestazione che lo dichiara. Usa quell'intestazione.

Il tuo problema è ancora vago. Stai cercando di proteggere da qualcosa che non puoi.

Puoi aggiungere la seguente riga alla tua libreria client:

typedef struct INTERNAL_DATA *HandleType;

ma, se il nome / la struttura cambiano, potresti avere un po 'di cattiveria.

Prova i modelli:

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

La dichiarazione in avanti va bene. Se si intende utilizzare puntatori o riferimenti, è necessaria solo una dichiarazione di classe ( __INTERNAL_DATA ) nell'ambito. Tuttavia, se si intende utilizzare una funzione membro o un oggetto, è necessario includere l'intestazione.

Altri suggerimenti

Se il tipo si trova in una libreria di terze parti, il grande vantaggio della dichiarazione a termine (isolare le ricostruzioni a causa di cambiamenti nelle intestazioni) viene effettivamente perso.

Se sei preoccupato per i tempi di compilazione (è un'intestazione considerevole), forse puoi metterlo in un'intestazione precompilata o includere semplicemente l'intestazione pertinente da una libreria.

es. molte intestazioni di libreria sembrano

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

Se definito in questo modo (tutto su una riga), allora __INTERNAL DATA fa parte dell'interfaccia pubblica quanto HandleType.

Tuttavia, non credo che __INTERNAL_DATA esista effettivamente. Molto probabilmente, HandleType è davvero (internamente) un int. Questa strana definizione è solo un modo per definirla in modo che abbia le stesse dimensioni di un int, ma distinta, in modo che il compilatore ti dia un errore se provi a passare un int in cui dovresti passare un HandleType. Il venditore della biblioteca avrebbe potuto facilmente definirlo come " int " o " void * " ;, ma in questo modo otteniamo un controllo del tipo.

Quindi __INTERNAL_DATA è solo una convenzione e non cambierà.


AGGIORNAMENTO: quanto sopra è stato un po 'un rutto mentale ... OK, __INTERNAL_DATA sicuramente non esiste. Lo sappiamo per certo, perché possiamo vedere la sua definizione come una struttura vuota. Immagino che la libreria di terze parti utilizzi " C " collegamento esterno (nessun nome gestibile), nel qual caso basta copiare il typedef - andrà bene.

All'interno della libreria stessa, HandleType avrà una definizione completamente diversa; forse int , forse " struct MyStruct {.......} * " ;.

Se davvero, davvero, davvero non vuoi esporre _INTERNAL_DATA al chiamante, la tua unica vera scelta è usare typedef void * HandleType ; Quindi all'interno della tua libreria puoi fare tutto quello che vuoi, inclusa la modifica dell'intera implementazione di * HandleType.

Basta creare una funzione di supporto per accedere ai tuoi dati reali.

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

Non sono del tutto sicuro di cosa stai cercando, ma funzionerà senza includere il file di intestazione effettivo:

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

Intendiamoci, dovrai comunque avere accesso ai membri pubblici di __INTERNAL_DATA all'interno del corpo del costruttore.

modifica: come sottolineato da James Curran, la struttura __INTERNAL_DATA non ha membri, quindi può essere usata, come sopra, senza problemi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top