Я начинающий программист, все еще пытаюсь изучить основы проектирования C ++ и ООП. Проект, над которым я работал, — это игра C ++, в которой есть несколько классов, файлов, состояний и т. Д. Однако я продолжаю сталкиваться с трудностями в организации файлов, которые варьируются от простой борьбы с тем, где создавать объекты до компиляции. ломать ошибки компоновщика.
Вот пример некоторых ошибок, которые я получаю:
1>SMGA.obj : error LNK2005: "class Engine smgaEngine" (?smgaEngine@@3VEngine@@A) already defined in Engine.obj
1>SplashScreenState.obj : error LNK2005: "class Engine smgaEngine" (?smgaEngine@@3VEngine@@A) already defined in Engine.obj
1>StateManager.obj : error LNK2005: "class StateManager gameStateManager" (?gameStateManager@@3VStateManager@@A) already defined in Engine.obj
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
Я смотрел в Интернете и видел много похожих проблем, которые включают в себя плохую защиту и включение файлов .cpp вместо файлов .h. Но я не сделал этого в своем коде, поэтому я в растерянности.
Теперь я предполагаю, что ошибка говорит мне, что я пытаюсь создать объект smgaEngine класса Engine (и объект gameStateManager класса StateManager) дважды, но я не уверен, почему …
Особенность этих двух объектов (smgaEngine и gameStateManager) заключается в том, что я объявил их в соответствующих файлах класса .h сразу после объявления класса. Может ли это быть проблемой? — Они все еще находятся в пределах включенных охранников, и я не был слишком уверен, где еще можно поместить их в мой код … Будет ли это неаккуратное кодирование причиной ошибок компоновщика?
Вот один из подозрительных классов …
#ifndef ENGINE_H
#define ENGINE_H
#include <SDL.h>
#include "Timer.h"
class Engine
{
private:
static const int screenWidth = 480;
static const int screenHeight = 270;
static const int screenBPP = 24;
bool running;
SDL_Surface *mainScreen;
SDL_Event eventHolder;
Timer fpsTimer;
public:
Engine();
~Engine();
void init();
void handleEvents();
void handleLogic();
void handleRender();
void cleanUp();
SDL_Event *getEvent();
SDL_Surface *getMainScreen();
bool isRunning();
void setRunning(bool tempRunning);
} smgaEngine;
#endif
А вот и другой:
#ifndef STATEMANAGER_H
#define STATEMANAGER_H
#include "SplashScreenState.h"#include <vector>
class GameState;
class StateManager
{
private:
std::vector<GameState*> stateStack;
SplashScreenState *splashState;
public:
StateManager();
~StateManager();
void init();
void changeState( GameState *tempNextState );
void addState( GameState *tempNextState );
void removeState();
//returns the back() element of the stateStack vector..
GameState* getTopState();
void handleEvents();
void handleLogic();
void handleRender();
} gameStateManager;
#endif
Я старался изо всех сил изучать C ++ и ООП, но я действительно боролся. Кажется, что каждый раз, когда я пытаюсь создать чистый код с инкапсулированными классами, я сталкиваюсь с путаницей. Я пытаюсь предотвратить высокую степень связывания классов, но я часто сталкиваюсь либо с ошибками компоновщика, либо с неспособностью связываться между классами … Является ли создание объектов экземпляра класса в заголовочных файлах причиной этих ошибок Или что-то еще? И если это является причиной моих ошибок компоновщика, то где я должен создавать эти объекты?
Вы определили две глобальные переменные, smgaEngine
а также gameStateManager
в заголовочных файлах, и вы включили эти заголовочные файлы в два (или более) исходных файла. Таким образом, вы получаете несколько ошибок определения. Защитные устройства не предотвращают включение файлов заголовков дважды в разные исходные файлы (как они могут?), Они останавливают включение файлов заголовков дважды в так же исходный файл.
Вы достаточно близки к правильному ответу (по крайней мере, у вас есть хорошее понимание проблемы). Правильный путь это
// header file Engine.h
class Engine
{
};
extern Engine smgaEngine;
// in one source file (say Engine.cpp)
Engine smgaEngine;
Что у вас есть сейчас декларация в заголовочном файле (extern
делает это декларацией), но определение в исходном файле. Вы можете иметь столько объявлений, сколько захотите (при условии, что они непротиворечивы), но у вас должно быть только одно определение. Поэтому для глобальных переменных поместите объявления в заголовочный файл и поместите определение в один из исходных файлов.
Других решений пока нет …