C++ #include
Rozwiązany
To, co naprawdę mi pomogło, to to, że mogłem # zawierać nagłówki w .plik cpp z out powodujący błąd redefinicji.
Jestem nowy w C++ , ale mam pewne doświadczenie w programowaniu w C# i Javie, więc może mi zabraknąć czegoś podstawowego, co jest unikalne dla C++.
Problem polega na tym, że nie bardzo wiem, co jest nie tak, wkleję jakiś kod, aby spróbować wyjaśnić problem.
Mam trzy klasy, GameEvents, fizykę i GameObject. Mam nagłówki dla każdego z oni. GameEvents ma jedną fizykę i listę obiektów GameObjects. Fizyka ma listę obiektów GameObjects.Próbuję osiągnąć to, że chcę, aby GameObject mógł uzyskać dostęp lub posiadać obiekt fizyczny.
Jeśli po prostu #włączę " fizykę.h " W GameObject dostaję "error C2111: 'ClassXXX': 'class' type redifinition ' co rozumiem. I tu pomyślałem, że #include-guards pomoże, więc dodałem include guard do mojej fizyki.h ponieważ jest to nagłówek, który chcę zawrzeć dwa razy.
Tak to wygląda
#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
Ale jeśli # włączę " fizykę.h " w mojej grze.h teraz tak:
#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();
};
Mam wiele problemów, które nie rozumieją, dlaczego się pojawiają.
Jeśli nie # include " Fizyka.h " mój kod działa dobrze.
Jestem bardzo wdzięczny za każdą pomoc. 6 answers
Preprocesor jest programem, który pobiera Twój program, wprowadza pewne zmiany (na przykład pliki nagłówkowe (#include), rozszerzenie makr (#define) i w zasadzie wszystko, co zaczyna się od #
) i daje "czysty" wynik kompilatorowi.
Preprocesor działa tak, gdy widzi #include
:
Kiedy piszesz:
#include "some_file"
Zawartość some_file
prawie dosłownie zostaje wklejona do pliku wraz z nią. Teraz, jeśli mieć:
a.h:
class A { int a; };
I:
b.h:
#include "a.h"
class B { int b; };
I:
main.cpp:
#include "a.h"
#include "b.h"
Otrzymujesz:
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"
Teraz możesz zobaczyć, jak A
jest redefiniowane.
Kiedy piszesz strażnicy, stają się tak:
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
Przyjrzyjmy się więc teraz, jak #include
s W main będzie rozszerzony (jest to dokładnie tak, jak w poprzednim przypadku: kopiuj-wklej)
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
Teraz podążajmy za preprocesorem i zobaczmy, jaki "prawdziwy" kod z tego wyjdzie. Pójdę linia po linii:
// From #include "a.h"
Skomentuj. Ignoruj! Dalej:
#ifndef A_H
Czy A_H
jest zdefiniowany? Nie! Następnie kontynuuj:
#define A_H
Ok teraz A_H
jest zdefiniowana. Dalej:
class A { int a; };
To nie jest coś dla preprocesora, więc zostaw to. Dalej:
#endif
Poprzedni if
skończył się tutaj. Dalej:
// From #include "b.h"
Skomentuj. Ignoruj! Dalej:
#ifndef B_H
Czy B_H
jest zdefiniowany? Nie! Następnie kontynuuj:
#define B_H
Ok teraz B_H
jest zdefiniowana. Dalej:
#ifndef A_H // From
Czy A_H
jest zdefiniowany? Tak! Wtedy ignoruj do momentu odpowiadającego #endif
:
#define A_H // #include "a.h"
Ignoruj
class A { int a; }; // inside
Ignoruj
#endif // "b.h"
Poprzedni if
skończył się tutaj. Dalej:
class B { int b; };
To nie jest coś dla preprocesora, więc zostaw to. Dalej:
#endif
Poprzedni if
skończył się tutaj.
To znaczy, po wykonaniu preprocesora z plikiem, to jest to, co widzi kompilator:
main.cpp
class A { int a; };
class B { int b; };
Więc jak widzisz, wszystko, co może dostać #include
d w tym samym pliku dwa razy, bez względu na to, czy należy go strzec bezpośrednio czy pośrednio. Ponieważ pliki .h
są zawsze bardzo prawdopodobne, że zostaną dołączone dwa razy, dobrze jest, jeśli strzeżysz wszystkich swoich .pliki H.
P. S. zauważ, że masz również okrągłe #include
s. wyobraź sobie, że preprocesor kopiuje kod fizyki.h do GameObject.h, który widzi, że istnieje #include "GameObject.h"
, co oznacza kopię GameObject.h
w sobie. Kiedy kopiujesz, znowu dostajesz #include "Pysics.h"
i utknąłeś w pętli na zawsze. Kompilatory temu zapobiegają, ale to oznacza, że twoje #include
s są połowa skończona.
Jeśli masz:
#include "b.h"
class A
{
B b;
};
Następnie kompilator musi wiedzieć wszystko o b
, co najważniejsze, jakie ma zmienne itp., aby wiedział, ile bajtów powinien umieścić w miejscu b
w A
.
Jednakże, jeśli masz:
class A
{
B *b;
};
Wtedy kompilator tak naprawdę nie musi nic wiedzieć o B
(ponieważ wskaźniki, niezależnie od typu mają takie same rozmiar). Jedyne, co musi wiedzieć o B
, to to, że istnieje!
Więc robisz coś, co nazywa się "forward declaration":
class B; // This line just says B exists
class A
{
B *b;
};
Jest to bardzo podobne do wielu innych rzeczy, które robisz w plikach nagłówkowych, takich jak:
int function(int x); // This is forward declaration
class A
{
public:
void do_something(); // This is forward declaration
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-10 20:39:09
Masz tutaj odniesienia okrągłe: Physics.h
zawiera GameObject.h
który zawiera Physics.h
. Twoja klasa Physics
używa GameObject*
(pointer) type, więc nie musisz dołączać GameObject.h
do Physics.h
, ale po prostu użyj deklaracji forward-zamiast
#include "GameObject.h"
Put
class GameObject;
Ponadto umieść osłony w każdym pliku nagłówkowym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 12:26:46
Problem polega na tym, że twój GameObject.h
nie ma strażników, więc kiedy #include "GameObject.h"
w Physics.h
zostanie uwzględniony, gdy GameObject.h
zawiera Physics.h
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 12:19:23
Dodaj osłony include we wszystkich plikach nagłówkowych *.h
LUB *.hh
(chyba że masz konkretne powody, aby tego nie robić).
Aby zrozumieć, co się dzieje, spróbuj uzyskać wstępnie przetworzoną formę kodu źródłowego. Z GCC jest to coś w rodzaju g++ -Wall -C -E yourcode.cc > yourcode.i
(nie mam pojęcia jak kompilatory Microsoftu to robią). Możesz również zapytać, które pliki są dołączone, z GCC jako g++ -Wall -H -c yourcode.cc
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 12:19:49
Po pierwsze musisz również włączyć strażników w gameobject, ale to nie jest prawdziwy problem
Jeśli coś innego zawiera fizykę.najpierw fizyka.h obejmuje gameobject.H, dostajesz coś takiego:
class GameObject {
...
};
#include physics.h
class Physics {
...
};
Oraz #include physics.h zostaje odrzucony z powodu strażników include, a Ty kończysz z deklaracją GameObject przed deklaracją fizyki.
Ale to jest problem, jeśli chcesz GameObject mieć wskaźnik do fizyki, ponieważ dla fizyki htat musiałby być zadeklarowany jako pierwszy.
Aby rozwiązać cykl, możesz zamiast tego zadeklarować klasę forward-declare, ale tylko wtedy, gdy używasz jej jako wskaźnika lub odniesienia w poniższej deklaracji, tj.:
#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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 12:27:34
Użyj include guards w WSZYSTKICH Twoich plikach nagłówkowych. Ponieważ używasz Visual Studio, możesz użyć #pragma once
jako pierwszej definicji preprocesora we wszystkich nagłówkach.
Proponuję jednak zastosować podejście Klasyczne:
#ifndef CLASS_NAME_H_
#define CLASS_NAME_H_
// Header code here
#endif //CLASS_NAME_H_
Po drugie przeczytaj o deklaracji forward i zastosuj ją.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 12:42:37