Inoltra dichiarare puntatori a strutture in C ++
-
08-07-2019 - |
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.
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.