likes hashtags for followers app c++ header include include-guards

hashtags - C++#incluye guardias



tags for likes instagram 2017 (6)

Agregue incluir guardias en todos sus archivos de encabezado *.h o *.hh (a menos que tenga razones específicas para no hacerlo).

Para comprender lo que está sucediendo, intente obtener la forma preprocesada de su código fuente. Con GCC, es algo así como g++ -Wall -C -E yourcode.cc > yourcode.i (no tengo idea de cómo lo hacen los compiladores de Microsoft). También puede preguntar qué archivos están incluidos, con GCC como g++ -Wall -H -c yourcode.cc

SOLUCIONADO

Lo que realmente me ayudó fue que pude #incluir encabezados en el archivo .cpp sin causar el error redefinido.

Soy nuevo en C ++, pero tengo algo de experiencia en programación en C # y Java, así que podría estar perdiendo algo básico que es exclusivo de C ++.

El problema es que realmente no sé lo que está mal, pegaré un código para tratar de explicar el problema.

Tengo tres clases, GameEvents, Physics y GameObject. Tengo encabezados para cada uno de ellos. GameEvents tiene una Física y una lista de GameObjects. Física tiene una lista de GameObjects.

Lo que intento lograr es que quiera que GameObject pueda acceder o ser dueño de un objeto de Física.

Si simplemente # incluyo "Physics.h" en GameObject obtengo el "error C2111: ''ClassXXX'': ''clase'' de tipo redifinition" que entiendo. Y aquí es donde pensé que # incluir-guardias ayudaría, así que agregué un protector de inclusión a mi Physics.h ya que ese es el encabezado que quiero incluir dos veces.

Así es como se ve

#ifndef PHYSICS_H #define PHYSICS_H #include "GameObject.h" #include <list> class Physics { private: double gravity; list<GameObject*> objects; list<GameObject*>::iterator i; public: Physics(void); void ApplyPhysics(GameObject*); void UpdatePhysics(int); bool RectangleIntersect(SDL_Rect, SDL_Rect); Vector2X CheckCollisions(Vector2X, GameObject*); }; #endif // PHYSICS_H

Pero si #incluyo "Física.h" en mi GameObject.h ahora de esta manera:

#include "Texture2D.h" #include "Vector2X.h" #include <SDL.h> #include "Physics.h" class GameObject { private: SDL_Rect collisionBox; public: Texture2D texture; Vector2X position; double gravityForce; int weight; bool isOnGround; GameObject(void); GameObject(Texture2D, Vector2X, int); void UpdateObject(int); void Draw(SDL_Surface*); void SetPosition(Vector2X); SDL_Rect GetCollisionBox(); };

Recibo múltiples problemas que no entienden por qué aparecen. Si no # incluye "Física.h" mi código funciona bien.

Estoy muy agradecido por cualquier ayuda.


El preprocesador es un programa que toma su programa, realiza algunos cambios (por ejemplo, incluye archivos (#include), expansión de macros (#define) y básicamente todo lo que comienza con # ) y le da el resultado "limpio" al compilador.

El preprocesador funciona así cuando ve #include :

Cuando escribes:

#include "some_file"

El contenido de some_file literalmente casi literalmente el archivo que lo incluye. Ahora si tienes:

a.h: class A { int a; };

Y:

b.h: #include "a.h" class B { int b; };

Y:

main.cpp: #include "a.h" #include "b.h"

Usted obtiene:

main.cpp: class A { int a; }; // From #include "a.h" class A { int a; }; // From #include "b.h" class B { int b; }; // From #include "b.h"

Ahora puedes ver cómo A se redefine.

Cuando escribes guardias, se vuelven así:

a.h: #ifndef A_H #define A_H class A { int a; }; #endif b.h: #ifndef B_H #define B_H #include "a.h" class B { int b; }; #endif

Entonces, veamos cómo se expandiría #include s en main (esto es exactamente, como en el caso anterior: copiar y pegar)

main.cpp: // From #include "a.h" #ifndef A_H #define A_H class A { int a; }; #endif // From #include "b.h" #ifndef B_H #define B_H #ifndef A_H // From #define A_H // #include "a.h" class A { int a; }; // inside #endif // "b.h" class B { int b; }; #endif

Ahora sigamos al preprocesador y veamos qué código "real" surge de esto. Voy a ir línea por línea:

// From #include "a.h"

Comentario. ¡Ignorar! Continuar:

#ifndef A_H

¿ A_H definido A_H ? ¡No! Luego continúa:

#define A_H

Ok, ahora A_H está definido. Continuar:

class A { int a; };

Esto no es algo para el preprocesador, así que déjalo. Continuar:

#endif

El anterior if terminó aquí. Continuar:

// From #include "b.h"

Comentario. ¡Ignorar! Continuar:

#ifndef B_H

¿Está B_H definido? ¡No! Luego continúa:

#define B_H

Ok, ahora B_H está definido. Continuar:

#ifndef A_H // From

¿ A_H definido A_H ? ¡SÍ! Luego ignore hasta el correspondiente #endif :

#define A_H // #include "a.h"

Ignorar

class A { int a; }; // inside

Ignorar

#endif // "b.h"

El anterior if terminó aquí. Continuar:

class B { int b; };

Esto no es algo para el preprocesador, así que déjalo. Continuar:

#endif

El anterior if terminó aquí.

Es decir, después de que el preprocesador haya terminado con el archivo, esto es lo que ve el compilador:

main.cpp class A { int a; }; class B { int b; };

Entonces, como puede ver, cualquier cosa que pueda obtener #include d en el mismo archivo dos veces, ya sea directa o indirectamente, debe ser protegida. Como es muy probable que los archivos .h se incluyan dos veces, es bueno que proteja TODOS sus archivos .h.

PS Tenga en cuenta que también tiene #include s circular. Imagine el preprocesador copiando y pegando el código de Physics.h en GameObject.h que ve que hay un #include "GameObject.h" que significa copiar GameObject.h en sí mismo. Cuando copias, nuevamente obtienes #include "Pysics.h" y estás atrapado en un ciclo para siempre. Los compiladores lo evitan, pero eso significa que sus #include están medio hechos.

Antes de decir cómo arreglar esto, debes saber otra cosa.

Si usted tiene:

#include "b.h" class A { B b; };

Entonces el compilador necesita saber todo sobre b , lo que es más importante, qué variables tiene, etc. para saber cuántos bytes debería poner en lugar de b en A

Sin embargo, si tiene:

class A { B *b; };

Entonces, el compilador realmente no necesita saber nada sobre B (ya que los punteros, independientemente del tipo, tienen el mismo tamaño). ¡Lo único que necesita saber sobre B es que existe!

Entonces haces algo llamado "declaración adelantada":

class B; // This line just says B exists class A { B *b; };

Esto es muy similar a muchas otras cosas que hace en archivos de encabezado como:

int function(int x); // This is forward declaration class A { public: void do_something(); // This is forward declaration }


El problema es que su GameObject.h no tiene guardias, por lo que cuando #include "GameObject.h" en Physics.h , se incluye cuando GameObject.h incluye Physics.h .


En primer lugar, debes incluir guardias en gameobject también, pero ese no es el problema real aquí

Si algo más incluye física.h primero, physics.h incluye gameobject.h, obtienes algo como esto:

class GameObject { ... }; #include physics.h class Physics { ... };

y el #include physics.h se descarta debido a los guardias de inclusión, y terminas con una declaración de GameObject antes de la declaración de Física.

Pero eso es un problema si quieres que GameObject tenga un puntero a Física, porque para eso la física debería declararse primero.

Para resolver el ciclo, puede reenviar-declarar una clase en su lugar, pero solo si solo lo está usando como un puntero o una referencia en la siguiente declaración, es decir:

#ifndef PHYSICS_H #define PHYSICS_H // no need for this now #include "GameObject.h" #include <list> class GameObject; class Physics { private: list<GameObject*> objects; list<GameObject*>::iterator i; public: void ApplyPhysics(GameObject*); Vector2X CheckCollisions(Vector2X, GameObject*); }; #endif // PHYSICS_H


Tiene referencias circulares aquí: Physics.h incluye GameObject.h que incluye Physics.h . La clase de Physics utiliza el tipo GameObject* (puntero), por lo que no es necesario que incluya GameObject.h en Physics.h sino que solo use la declaración de reenvío, en lugar de

#include "GameObject.h"

poner

class GameObject;

Además, coloca guardias en cada archivo de encabezado.


Utilice incluir guardias en TODOS sus archivos de encabezado. Como está utilizando Visual Studio, podría usar #pragma once como la primera definición de preprocesador en todos sus encabezados.

Sin embargo, sugiero usar el enfoque clásico:

#ifndef CLASS_NAME_H_ #define CLASS_NAME_H_ // Header code here #endif //CLASS_NAME_H_

Segunda lectura sobre la declaración directa y aplicarla.