Pregunta

Estoy usando una biblioteca de terceros que tiene una declaración como esta:

typedef struct {} __INTERNAL_DATA, *HandleType;

Y me gustaría crear una clase que tome un HandleType en el constructor:

class Foo
{
    Foo(HandleType h);
}

sin incluido el encabezado que define HandleType . Normalmente, simplemente declararía hacia adelante tal tipo, pero no puedo entender la sintaxis para esto. Tengo muchas ganas de decir algo como:

struct *HandleType;

Pero eso dice " Identificador esperado antes de * " en el CCG. La única solución que puedo ver es escribir mi clase de esta manera:

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

Pero esto se basa en detalles internos de la biblioteca. Es decir, utiliza el nombre __INTERNAL_DATA, que es un detalle de implementación.

Parece que debería ser posible declarar adelante HandleType (parte de la API pública) sin usar __INTERNAL_DATA (parte de la implementación de la biblioteca). ¿Alguien sabe cómo?

EDITAR: se agregaron más detalles sobre lo que estoy buscando.

¿Fue útil?

Solución

Update:

  

Lo estoy usando en la implementación .cpp de Foo, pero quiero evitar incluirlo en mi encabezado .h para Foo. ¿Quizás solo estoy siendo demasiado pedante? :)

Sí, lo estás :) Sigue adelante con la declaración hacia adelante.

Si HandleType es parte de la interfaz, debe haber un encabezado que lo declare. Usa ese encabezado.

Su problema sigue siendo vago. Estás tratando de protegerte contra algo que no puedes.

Puede agregar la siguiente línea a su biblioteca cliente:

typedef struct INTERNAL_DATA *HandleType;

pero, si el nombre / la estructura cambian, es posible que tengas un poco de maldad de lanzamiento.

Pruebe plantillas:

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

La declaración de reenvío está bien. Si va a utilizar punteros o referencias, solo necesita una declaración de clase ( __INTERNAL_DATA ) en su alcance. Sin embargo, si va a utilizar una función miembro o un objeto, deberá incluir el encabezado.

Otros consejos

Si el tipo está en una biblioteca de terceros, entonces el gran beneficio de la declaración hacia adelante (aislar reconstrucciones debido a cambios en los encabezados) se pierde efectivamente.

Si le preocupan los tiempos de compilación (es un encabezado considerable), entonces quizás pueda colocarlo en un encabezado precompilado o simplemente incluir el encabezado relevante de una biblioteca.

Por ejemplo. muchos encabezados de biblioteca se parecen

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

Si se define así (todo en una línea), entonces __INTERNAL DATA es una parte tan importante de la interfaz pública como HandleType.

Sin embargo, no creo que __INTERNAL_DATA realmente exista. Más que probable, HandleType es realmente (internamente) un int. Esta definición extraña es solo una forma de definirla para que tenga el mismo tamaño que un int, pero distinta, de modo que el compilador le dé un error si intenta pasar un int donde se supone que debe pasar un HandleType. El proveedor de la biblioteca podría haberlo definido tan fácilmente como "int" o " nulo * " ;, pero de esta manera obtenemos alguna verificación de tipo.

Por lo tanto, __INTERNAL_DATA es solo una convención y no va a cambiar.


ACTUALIZACIÓN: Lo anterior fue un poco un eructo mental ... OK, __INTERNAL_DATA definitivamente no existe. Sabemos esto de hecho, porque podemos ver su definición como una estructura vacía. Voy a adivinar que la biblioteca de terceros usa " C " enlace externo (sin gestión de nombre), en cuyo caso, solo copie el typedef - estará bien.

Dentro de la propia biblioteca, HandleType tendrá una definición completamente diferente; tal vez int , tal vez " struct MyStruct {.......} * " ;.

Si realmente no desea exponer _INTERNAL_DATA a la persona que llama, su única opción real es usar typedef void * HandleType ; Luego, dentro de su biblioteca, puede hacer lo que quiera, incluso cambiar la implementación completa de * HandleType.

Simplemente cree una función auxiliar para acceder a sus datos reales.

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

No estoy muy seguro de lo que está buscando, pero lo siguiente funcionará sin incluir el archivo de encabezado real:

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

Eso sí, aún tendrá que tener acceso a los miembros públicos de __INTERNAL_DATA dentro del cuerpo del constructor.

edit: como señaló James Curran, la estructura __INTERNAL_DATA no tiene miembros, por lo que puede usarse, como se indicó anteriormente, sin problemas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top