C++ #include gardes
RÉSOLU
Ce qui m'a vraiment aidé est que je pouvais #inclure les en-têtes de dans le .fichier cpp avec provoquant la redéfinition d'erreur.
Je suis novice en C++, mais j'ai une certaine expérience de la programmation en C# et en Java, donc j'ai peut être raté quelque chose de base qui est unique à C++.
Le problème est que je ne sais pas vraiment quel est le problème, je vais coller un peu de code pour essayer d'expliquer le problème.
J'ai trois Classes, GameEvents, de la Physique et de la GameObject. J'ai les en-têtes pour chacun d'eux.
GameEvents a un Physique et une liste des GameObjects.
La physique a une liste des GameObjects.
Ce que je suis en train de réaliser, c'est que je veux GameObject pour être en mesure d'accéder ou de posséder un objet Physique.
Si j'ai simplement #include "de la Physique.h" dans GameObject-je obtenir les
"erreur C2111: 'ClassXXX' : 'class' type de redéfinition" que je comprends.
Et c'est là que j'ai pensé #include-gardes de l'aide j'ai donc ajouté un include de la garde à mon Physique.h puisque c'est l'en-tête, je veux inclure deux fois.
C'est à quoi il ressemble
#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
Mais si j' #include "de la Physique.h" dans mon GameObject.h maintenant comme ceci:
#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();
};
Je obtenir plusieurs questions qui ne comprennent pas pourquoi ils sont en train d'apparaître.
Si je n'ai pas #include "de la Physique.h" mon code fonctionne très bien.
Je suis très reconnaissant pour toute aide.
- Double de stackoverflow.com/questions/8010601/... et beaucoup d'autres.
Vous devez vous connecter pour publier un commentaire.
Le préprocesseur est un programme qui prend votre programme, apporte quelques modifications (par exemple inclure des fichiers (#include), la macro-expansion (#define), et en gros, tout ce qui commence avec
#
) et donne le "nettoyer" le résultat de la compilation.Le préprocesseur œuvres de ce genre quand il voit
#include
:Lorsque vous écrivez:
Le contenu de
some_file
presque littéralement obtenir une copie collé dans le fichier, y compris elle. Maintenant, si vous avez:Et:
Et:
Vous bénéficiez de:
Maintenant, vous pouvez voir comment
A
est redéfini.Lorsque vous écrivez des gardes, ils deviennent comme ceci:
Alors maintenant, regardons comment
#include
s en principal serait élargie (c'est exactement, comme dans le cas précédent: le copier-coller)Maintenant, nous allons suivre le préprocesseur et voir ce que les "vrais" code vient de là. Je vais aller ligne par ligne:
Commentaire. Ignorez-le! Continuer:
Est
A_H
défini? Non! Puis continuer:Ok maintenant
A_H
est défini. Continuer:Ce n'est pas quelque chose de préprocesseur, il suffit donc de le laisser être. Continuer:
La précédente
if
fini ici. Continuer:Commentaire. Ignorez-le! Continuer:
Est
B_H
défini? Non! Puis continuer:Ok maintenant
B_H
est défini. Continuer:Est
A_H
défini? OUI! Puis de les ignorer jusqu'à ce correspondant#endif
:Ignorer
Ignorer
La précédente
if
fini ici. Continuer:Ce n'est pas quelque chose de préprocesseur, il suffit donc de le laisser être. Continuer:
La précédente
if
fini ici.Qui est, après le préprocesseur est fait avec le fichier, c'est ce que le compilateur voit:
Donc, comme vous pouvez le voir, tout ce que l'on peut obtenir
#include
d en deux fois le même fichier, que ce soit directement ou indirectement, doit être surveillé. Depuis.h
les fichiers sont toujours très susceptibles d'être inclus deux fois, c'est bon si tu gardes TOUS vos .h fichiers.P. S. Notez que vous avez également la circulaire
#include
s. Imaginez le préprocesseur copier-coller le code de la Physique.h en GameObject.h, qui voit, il y a un#include "GameObject.h"
qui signifie copieGameObject.h
en lui-même. Lorsque vous copiez, vous pouvez à nouveau obtenir#include "Pysics.h"
et vous êtes coincé dans une boucle pour toujours. Les compilateurs de l'en empêcher, mais cela signifie que votre#include
s sont à moitié fait.Avant de dire comment résoudre ce problème, vous devez savoir une autre chose.
Si vous avez:
Ensuite, le compilateur a besoin de tout savoir sur
b
, plus important encore, quelles variables il a etc de sorte qu'il serait de savoir combien d'octets il devrait mettre en place desb
dansA
.Toutefois, si vous avez:
Puis le compilateur n'a pas vraiment besoin de savoir quelque chose au sujet de
B
(puisque les pointeurs, quel que soit le type ont la même taille). La seule chose qu'il a besoin de savoir à propos deB
est qu'il existe!Si vous faites quelque chose appelé "déclaration anticipée":
C'est très semblable à beaucoup d'autres choses que vous faites dans les fichiers d'en-tête comme:
Physics
objet ou d'un pointeur dans votreGameObject
classe, mais je vois beaucoup deGameObject *
s dans votrePhysics
classe. Cela donne à penser avant de déclarerGameObject
dansPhysics.h
plutôt que l'inverse. De toute façon, lorsque vous souhaitez utiliser la classe (c'est dans le.cpp
fichiers), vous devez inclure chaque en-tête de lui-même. Puisque vous n'avez pas inclure.cpp
fichiers, il n'y a pas de risque de la circulaire comprend!A_H
etB_H
dans#define
qui n'ont pas paru (défini) avant? Comment sait-il qui sont liées à desa.h
oub.h
?#include
d. Puis, il commence à regarder à l'intérieur. La première fois qu'il voit#define A_H
, bien qu'il la définit. En fait, c'définir ne devrait pas arriver deux foisA_H
a été défini, comme un fichier nomméA_H
. Je pense que ce que vous dites, c'est que les lignes entre#define A_H
et#endif
est la définition deA_H
. Donc, en fait, vous pouvez dire quelque chose de complètement étranger àa.h
oub.h
. Suis-je le droit?#define A_H
n'est pas pris en sandwich entre#ifndef
et#endif
mais ailleurs, et s'étend sur plusieurs lignes ci-dessous#define
, comment le compilateur de savoir où la définition de l'A_H
se termine si ce n'est pas la notation comme#enddef
?#define
est contenue dans la même ligne. Par exemple#define SOME_SYMBOL (some_expression)
signifie que le préprocesseur de remplacerSOME_SYMBOL
où elle voit à partir de ce point avec(some_expression)
. Si vous avez#define SOME_SYMBOL
avec rien en face de lui, il serait de remplacer tous les il la voit plus rien. Donc#define A_H
signifie "définir un symbole nomméA_H
qui remplace avec rien". La partie qui est important pour nous, c'est la "définition d'un symbole nomméA_H
", parce que plus tard, nous voulons avoir un si sur si le symbole est défini (#ifndef
).A_H
pour fichier nomméa.h
juste pour ressembler à elle. Vous pourriez avoir utilisé tous les autres symboles, tels queSWEET_HEADER_OF_MINE
. Toutefois, en nommant la garde symbole le même que le fichier d'en-tête (ou dérivé) permet d'éviter les collisions de noms parmi de nombreux en-têtes. Si vous utilisez le même garde symbole pour deux en-têtes, vous pouvez imaginer ce qui allait se passer (le deuxième en-tête inclus serait ignorée, car ce symbole est déjà défini dans le premier en-tête).class A {int a}
n'a rien à voir avec#define A_H
et il est vraiment partie de#ifndef...#endif' right? Also
#define A_H` avecA_H
être attribué rien n'est là que pour faire officiellementA_H
défini, non?char*
etvoid*
doit être assez grand pour que vous pouvez lancer à eux et à l'arrière, sans perte de données. (Il y a eu des cas d'applications oùsizeof (void*) > sizeof(struct t*)
.)Vous avez des références circulaires ici:
Physics.h
comprendGameObject.h
qui comprendPhysics.h
. Votre classePhysics
utiliseGameObject*
(pointeur) type de sorte que vous n'avez pas besoin d'inclureGameObject.h
dansPhysics.h
mais il suffit d'utiliser de l'avant de la déclaration au lieu demettre
En outre, de mettre des gardes dans chaque fichier d'en-tête.
Le problème est que votre
GameObject.h
n'a pas de gardes, de sorte que lorsque vous#include "GameObject.h"
dansPhysics.h
il est inclus lorsqueGameObject.h
comprendPhysics.h
.Ajouter sont gardes dans toutes vos
*.h
ou*.hh
fichiers d'en-tête (sauf si vous avez des raisons de ne pas le faire).À comprendre ce qui se passe, essayez d'obtenir la séquence de la forme de votre code source. Avec GCC, il est quelque chose comme
g++ -Wall -C -E yourcode.cc > yourcode.i
(je n'ai aucune idée sur la manière dont les compilateurs Microsoft à le faire). Vous pouvez également demander les fichiers qui sont inclus, avec GCC en tant queg++ -Wall -H -c yourcode.cc
Tout d'abord, vous devez inclure les gardes sur gameobject trop, mais ce n'est pas le vrai problème ici
Si quelque chose d'autre comprend la physique.h tout d'abord, la physique.h comprend gameobject.h, vous obtenez quelque chose comme ceci:
et le #include physique.h est rejeté en raison de l'inclure des gardes, et vous vous retrouvez avec une déclaration de GameObject avant la déclaration de la Physique.
Mais c'est un problème si vous voulez GameObject à avoir un pointeur vers une Physique, parce que pour htat physique devraient être déclarés en premier.
Pour résoudre le cycle, vous pouvez transmettre la déclaration d'une classe à la place, mais seulement si vous êtes juste de l'utiliser comme un pointeur ou une référence dans la déclaration suivante, à savoir:
Utilisation inclure des gardes dans TOUS vos fichiers d'en-tête. Puisque vous êtes à l'aide de Visual Studio, vous pouvez utiliser les
#pragma once
que la première définition de préprocesseur dans tous vos en-têtes.Cependant, je suggère d'utiliser l'approche classique:
Deuxième lecture sur avant la déclaration de et de l'appliquer.
L'objectif d'un en-tête de la garde est à éviter, y compris le même fichier plusieurs fois.
Mais l'en-tête de la garde qui est actuellement utilisé en C ++ peut être amélioré. L'actuel garde:
Ma nouvelle garde proposition est:
Cela résout le problème gênant qui se produit lorsque l'AAA les besoins de la classe la classe BBB déclaration, tandis que la classe BBB besoins de l'AAA de la déclaration de classe, généralement parce qu'il ya traversé les pointeurs d'une classe à l'autre:
J'aimerais pour que cela soit inclus dans les IDEs que de générer automatiquement du code à partir de modèles.