structs - tutorial struct c++
Declaraciones a futuro de la estructura sin nombre (12)
¿Por qué no evitas el forward decl?
Si la segunda definición estaba en un archivo de encabezado, podría incluir el archivo de encabezado primero en su archivo de encabezado C ++. Para hacer que C ++ piense que es un encabezado C, abrazar #include con extern "C" {
y }
debe ser suficiente en la mayoría de los casos.
Pregunta de Bounty: Entonces, estos dos Foo
no son lo mismo. Multa. La segunda forma se da en una biblioteca. ¿Cómo lo adelanto-declaro dado que no puedo cambiarlo?
Siempre pensé que C y C ++ permitían declaraciones repetidas siempre que no hubiera definiciones repetidas. Luego me encontré con este problema al tratar de escribir código C ++ que amplía una biblioteca C.
struct Foo;
typedef struct {} Foo;
Esto da el siguiente error:
''struct Foo'' tiene una declaración anterior como ''struct Foo''
Quiero reenviar-declarar, maldición! ¿Qué pasa aquí?
Creo que recientemente encontré el mismo problema que el póster original y lo resolví de la siguiente manera:
Estoy escribiendo un envoltorio alrededor de una API provista por terceros que se define como:
Foo.h:
typedef struct _foo
{
int i;
} Foo;
Foo* MakeFoo();
int UseFoo(Foo* foo);
Mi envoltorio debe tener a Foo como miembro, pero no quiero exponer a Foo a todos los consumidores de mi envoltorio.
UberFoo.h:
#pragma once
struct _foo; // forward declare the actual type _foo, not the typedef Foo
class UberFoo
{
public:
UberFoo();
int GetAnswer();
private:
_foo* f;
};
UberFoo.cpp:
#include "UberFoo.h"
#include "Foo.h"
UberFoo::UberFoo()
{
this->f = MakeFoo();
}
int UberFoo::GetAnswer()
{
return UseFoo(f);
}
Ahora, los consumidores de mi clase pueden crear una instancia sin tener acceso a la definición real de _foo / Foo. Esto también funcionaría si tuviera que pasar los punteros a _foo como parámetros o devolverlos de las funciones además de tener un miembro _foo.
main.cpp:
#include <cstdio>
#include "UberFoo.h"
int main(int argc, char* argv[])
{
UberFoo u;
printf( "The Answer = %d/n", u.GetAnswer());
return 0;
}
El truco aquí fue reenviar declarar el tipo de estructura real, no el nombre typedef''d. Tenga en cuenta que es crítico que la estructura no sea anónima, como es común en el código C antiguo:
typedef struct // the actual struct type underlying the typedef is anonymous here
{
int i;
} ThisWontWork;
¡Espero que esto ayude!
En mi humilde opinión, simplemente cambie su typedef
a,
typedef struct Foo {} Foo;
^^^^^
No hay daño y seguirá siendo compatible tanto en C & C ++. Ahora puedes reenviarlo declararlo.
[Nota: si aún insistes en no tocar el typedef
en absoluto, aquí está el truco sucio .
struct Foo;
#define struct struct Foo
#include"Foo.h" // contains typedef struct {} Foo;
#undef struct
Esto funcionará, solo si Foo.h
contiene solo 1 declaración de struct
. No lo recomiendo .]
En una situación similar, tengo un encabezado C heredado con algo así como
== old_library.h ==
typedef struct { int data; } Foo;
== /old_library.h ==
Lo uso en una clase C ++ propia, como parámetro para un método privado:
class C {
void run(Foo *ds);
...
}
Para evitar #include "old_library.h" de C.hpp, utilizo la siguiente declaración directa:
class C {
struct Foo;
void run(Foo *ds);
...
}
y en C.cpp tengo las siguientes declaraciones:
extern "C" {
#include "old_library.h"
}
struct C::Foo : public ::Foo {};
De esta manera, utilizo C :: Foo en lugar de Foo de forma transparente, ¡y no necesito un MyFoo!
Está intentando escribir un nombre previamente usado. La declaración es perfectamente válida, solo necesitas usar un nombre diferente.
struct Foo; // Forward declaration of struct Foo
typedef struct {} anotherFoo; // Another structure typedefed
struct Foo {
// Variables
}; // Definition of the forward declared Foo.
Tenga en cuenta que typedef no se puede usar con el mismo nombre.
Estás declarando dos entidades diferentes con el mismo nombre. El primero, struct Foo
, es una estructura llamada Foo
. El segundo es un alias para una estructura anónima .
Si lo haces en cambio:
struct Foo;
struct Foo {};
Funciona, porque estás declarando una estructura llamada Foo
en ambas situaciones.
No puede reenviar declarar estructuras anónimas. Te quedan dos opciones: incluir toda la definición o cambiar el encabezado y nombrar la estructura.
No necesita escribir estructuras dedef en C ++:
struct Foo; // Forward declaration
struct Foo
{
}; // Definition
Si quieres llamarlo simplemente Foo
lugar de struct Foo
en C, necesitas el typedef, que también se puede hacer de diferentes maneras:
struct Foo; /* Forward declaration */
struct Foo /* The name is needed here */
{
}; /* Definition */
typedef struct Foo Foo; /* typedef */
o
struct Foo; /* Forward declaration */
typedef struct Foo /* The name is needed here */
{
} Foo; /* Definition and typedef combined */
Por supuesto, puede usar la forma struct Foo
en C y C ++.
No puede reenviar declararlo, ya que no tiene nombre. Es una estructura sin nombre, para la cual Foo es un typedef.
Para una declaración directa de un typedef, necesita referirse a lo que está siendo defraudado, así como:
struct foo;
typedef foo bar;
class foo{};
Dado que desea reenviar declarar una estructura anónima, no puede darle un nombre en la declaración directa de la entidad original, ni puede referirse a ella cuando la defina. La sintaxis "lógica" sería:
struct ;
typedef bar;
class {};
Pero como esto obviamente no es posible, no puedes reenviar las estructuras anónimas.
Para ir al nivel estándar, echemos un vistazo a 9.1-2:
Una declaración que consiste únicamente en un identificador de clave de clase; es una redeclaración del nombre en el ámbito actual o una declaración directa del identificador como nombre de clase. Introduce el nombre de la clase en el alcance actual.
Sin identificador, sin declaración directa.
En pocas palabras: evite las estructuras anónimas a menos que le den una ventaja que realmente necesita.
Su compilador específico puede hacer una diferencia aquí.
Usando MinGW GCC 3.4.5, ambas declaraciones se compilan sin errores ni advertencias (usando -Wall
)
struct Foo;
typedef struct {} Foo;
y
struct Foo;
typedef struct Foo {} Foo;
¿Es posible que ya exista una declaración anticipada dentro de la biblioteca? Por ejemplo, para permitir un puntero circular:
struct Foo;
typedef struct Foo {
struct Foo *fooPtr;
} Foo;
Si esto ya existe dentro de los encabezados de la biblioteca, causaría el error que describes.
Su declaración directa declara que habrá una struct
llamada Foo
.
Su segunda declaración es de un tipo llamado Foo
. Estos no son la misma cosa.
typedef-ing anonymous struct es una práctica anterior a C ++ 03 y está principalmente orientada a mantener la compatibilidad con los compiladores anteriores a C99.
Dado que esto es 2011, y que tanto C ++ como C han cambiado, me pregunto por qué no hay una versión más actualizada de dicha biblioteca.
Si ya no está en desarrollo, no puedes "abandonar", sino simplemente "sobrevivir" y cambiarlo es la manera de hacerlo. Si aún está en implementación, envíe el problema al equipo de desarrollo.
Si necesita una solución alternativa, considere que struct puede heredar. Por lo tanto, escriba una declaración directa como
struct MyFoo;
y definirlo como
#include "old_library.h"
struct MyFoo: public Foo {};
Y en todo su código, olvídese de Foo
y siempre use MyFoo
.