Reputation: 639
I've been training to use object orientated programming in c++ but I keep getting this error:
1>main.obj : error LNK2005: "int WIDTH" (?WIDTH@@3HA) already defined in GameObject.obj
1>main.obj : error LNK2005: "int HEIGHT" (?HEIGHT@@3HA) already defined in GameObject.obj
1>Spaceship.obj : error LNK2005: "int WIDTH" (?WIDTH@@3HA) already defined in GameObject.obj
1>Spaceship.obj : error LNK2005: "int HEIGHT" (?HEIGHT@@3HA) already defined in GameObject.obj
1>C:\Users\ted\documents\visual studio 2010\Projects\fullSpace\Debug\fullSpace.exe : fatal error LNK1169: one or more multiply defined symbols found
However to me, it seems that the entire code is written properly and the two ints are only mentioned in the Global header and all objects seem to be inheriting properly. However, like I just said, I'm a beginner in OOP so I really need an opinion : It is also worth mentioning that I am using allegro 5 to create a side shooter.
This is the code :
(main):
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5\allegro_ttf.h>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#include <list>
#include "GameObject.h"
#include "Spaceship.h"
#include "Globals.h"
//controls
bool keys[] = {false, false, false, false, false};
enum KEYS{UP, DOWN, LEFT, RIGHT, SPACE};
//globals
Spaceship *ship;
std::list <GameObject *> objects;
std::list <GameObject *>::iterator iter;
std::list <GameObject *>::iterator iter2;
//prototypes
//main function
int main(int argc, char **argv)
{
//shell variables
bool done = false;
bool render = false;
float gameTime = 0;
int frames = 0;
int gameFPS = 0;
//project variables
ship = new Spaceship();
ALLEGRO_BITMAP *shipImage = NULL;
ALLEGRO_BITMAP *cometImage= NULL;
ALLEGRO_BITMAP *explImage = NULL;
ALLEGRO_BITMAP *bgImage = NULL;
ALLEGRO_BITMAP *mgImage = NULL;
ALLEGRO_BITMAP *plImage = NULL;
ALLEGRO_BITMAP *mgImage2 = NULL;
ALLEGRO_BITMAP *fgImage = NULL;
ALLEGRO_BITMAP *titleImage= NULL;
ALLEGRO_BITMAP *lostImage = NULL;
//allegro variables
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer;
ALLEGRO_FONT *font18;
//initiate variables
if(!al_init())
return -1;
display = al_create_display(WIDTH, HEIGHT);
if(!display)
return -1;
//addon installation
al_install_keyboard();
al_init_image_addon();
al_init_font_addon();
al_init_ttf_addon();
al_init_primitives_addon();
al_install_audio();
al_init_acodec_addon();
//project init
font18 = al_load_font("arial.ttf", 18, 0);
al_reserve_samples(15);
bgImage = al_load_bitmap("layer1.png");
mgImage = al_load_bitmap("layer2.png");
plImage = al_load_bitmap("starMG.png");
mgImage2 = al_load_bitmap("layer3.png");
fgImage = al_load_bitmap("layer4.png");
shipImage = al_load_bitmap("spaceship.png");
al_convert_mask_to_alpha(shipImage, al_map_rgb(255, 0, 255));
cometImage = al_load_bitmap("asteroid-1-96.png");
explImage = al_load_bitmap("explosion_3_40_128.png");
titleImage = al_load_bitmap("Shooter_Title.png");
lostImage = al_load_bitmap("Shooter_Lose.png");
//object init
ship->init(shipImage);
//iter list
objects.push_back(ship);
srand(time(NULL));
//timer init and startup
event_queue = al_create_event_queue();
timer = al_create_timer(1.0 / 60);
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_start_timer(timer);
gameTime = al_current_time();
while(!done)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
//input
if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = true;
break;
}
} else if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = false;
break;
case ALLEGRO_KEY_UP:
keys[UP] = false;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = false;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = false;
break;
}
}
else if (ev.type == ALLEGRO_EVENT_TIMER)
{
render = true;
//fps
frames++;
if(al_current_time() - gameTime >= 1)
{
gameTime = al_current_time();
gameFPS = frames;
frames = 0;
}
//shipUpdate
if(keys[UP])
ship ->moveUp();
else if(keys[DOWN])
ship ->moveDown();
else
ship->resetAnim(1);
if(keys[LEFT])
ship ->moveLeft();
else if(keys[RIGHT])
ship -> moveRight();
else
ship ->resetAnim(0);
}
//render
if(render && al_is_event_queue_empty(event_queue))
{
render = false;
//begin render
for(iter = objects.begin(); iter != objects.end(); ++iter)
(*iter)->render();
//Flip Buffers
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0));
}
}
//destroy objects
//visual objects
al_destroy_bitmap(cometImage);
for(iter = objects.begin(); iter != objects.end(); ++iter)
(*iter)->destroy(shipImage);
iter = objects.erase(iter);
al_destroy_bitmap(explImage);
al_destroy_bitmap(bgImage);
al_destroy_bitmap(mgImage);
al_destroy_bitmap(fgImage);
al_destroy_bitmap(titleImage);
al_destroy_bitmap(lostImage);
//audio objects
/*
al_destroy_sample(shot);
al_destroy_sample(boom);
al_destroy_sample(song);
al_destroy_sample_instance(songInstance);
*/
//shell objects
al_destroy_font(font18);
al_destroy_timer(timer);
al_destroy_event_queue(event_queue);
al_destroy_display(display);
return 0;
}
(Globals.h):
#pragma once
int WIDTH = 1024;
int HEIGHT = 800;
enum ID{PLAYER, ENEMY, BULLET, BORDER, MISC};
enum STATES{TITLE, PLAYING, LOST};
(GameObject.h):
#pragma once
#include "Globals.h"
#include <iostream>
#include <allegro5/allegro5.h>
#include <allegro5/allegro_primitives.h>
class GameObject
{
private:
int ID;
bool alive;
bool collidable;
protected:
float x;
float y;
float velX;
float velY;
int dirX;
int dirY;
int boundX;
int boundY;
int maxFrame;
int curFrame;
int frameCount;
int frameDelay;
int frameWidth;
int frameHeight;
int animationColumns;
int animationDirection;
ALLEGRO_BITMAP *image;
public:
GameObject();
void virtual destroy(ALLEGRO_BITMAP *image);
void init(float x, float y, float velX, float velY, int dirX, int dirY, int boundX, int boundY);
void virtual update();
void virtual render();
float getX() {return x;}
float getY() {return y;}
void setX(float x) {GameObject::x = x;}
void setY(float y) {GameObject::y = y;}
int getBoundX() {return boundX;}
int getBoundY() {return boundY;}
int getID() {return ID;}
void setID(int ID) {GameObject::ID = ID;}
bool getAlive() {return alive;}
void setAlive(bool alive) {GameObject::alive = alive;}
bool getCollidable() {return collidable;}
void setCollidable(bool collidable) {GameObject::collidable = collidable;}
bool checkCollisions(GameObject *otherObject);
void virtual collided(int objectID);
bool collidableCheck();
};
(GameObject.cpp):
#include "GameObject.h"
GameObject::GameObject()
{
x = 0;
y = 0;
velX = 0;
velY = 0;
dirX = 0;
dirY = 0;
boundX = 0;
boundY = 0;
maxFrame = 0;
curFrame = 0;
frameCount = 0;
frameDelay = 0;
frameWidth = 0;
frameHeight = 0;
animationColumns = 0;
animationDirection = 0;
image = NULL;
alive = true;
collidable = true;
}
void GameObject::destroy(ALLEGRO_BITMAP *image)
{
if(image != NULL)
al_destroy_bitmap(image);
}
void GameObject::init(float x, float y, float velX, float velY, int dirX, int dirY, int boundX, int boundY)
{
GameObject::x = x;
GameObject::y = y;
GameObject::velX = velX;
GameObject::velY = velY;
GameObject::dirX = dirX;
GameObject::dirY = dirY;
GameObject::boundX = boundX;
GameObject::boundY = boundY;
}
void GameObject::update()
{
x += velX*dirX;
y += velY*dirY;
}
void GameObject::render()
{
}
bool GameObject::checkCollisions(GameObject *otherObject)
{
float oX = otherObject->getX();
float oY = otherObject->getY();
int obX = otherObject->getBoundX();
int obY = otherObject->getBoundY();
if(x + boundX > oX - obX &&
x - boundX < oX + obX &&
y + boundY > oY - obY &&
y - boundY < oY + obY
)
return true;
else
return false;
}
void GameObject::collided(int objectID)
{
}
bool GameObject::collidableCheck()
{
return alive && collidable;
}
(SpaceShip.h):
#pragma once
#include "GameObject.h"
class Spaceship : public GameObject
{
private :
int lives;
int score;
int animationRow;
public :
Spaceship();
void destroy(ALLEGRO_BITMAP *image);
void init(ALLEGRO_BITMAP *image = NULL);
void update();
void render();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
void resetAnim(int pos);
int getLives(){return lives;}
int getScore() {return score;}
void looseLife() {lives--;}
void addPoint() {score++;}
void collide(int objectID);
};
(SpaceShip.cpp):
#include "Spaceship.h"
Spaceship::Spaceship()
{}
void Spaceship::destroy(ALLEGRO_BITMAP *image)
{
GameObject::destroy(image);
}
void Spaceship::init(ALLEGRO_BITMAP *image)
{
GameObject::init(20, 200, 6, 6, 0, 0, 10, 12);
setID(PLAYER);
setAlive(true);
lives = 3;
score = 0;
maxFrame = 3;
curFrame = 0;
frameWidth = 46;
frameHeight = 41;
animationColumns = 3;
animationDirection = 1;
animationRow = 1;
if(image != NULL)
{
Spaceship::image = image;
}
}
void Spaceship::update()
{
GameObject::update();
if(x < 0)
x=0;
else if ( x > WIDTH)
x = WIDTH;
if(y < 0)
y = 0;
else if (y > HEIGHT)
y = HEIGHT;
}
void Spaceship::render()
{
GameObject::render();
int fx = (curFrame % animationColumns) *frameWidth;
int fy = animationRow *frameHeight;
al_draw_bitmap_region(image, fx, fy, frameWidth, frameHeight,
x - frameWidth /2, y - frameHeight /2, 0);
}
void Spaceship::moveUp()
{
animationRow = 0;
dirY = -1;
}
void Spaceship::moveDown()
{
animationRow = 2;
dirY = 1;
}
void Spaceship::moveLeft()
{
curFrame = 2;
dirX = -1;
}
void Spaceship::moveRight()
{
curFrame = 1;
dirX = 1;
}
void Spaceship::resetAnim(int pos)
{
if(pos == 1)
{
animationRow = 1;
dirY = 0;
}
else
{
curFrame = 0;
dirX = 0;
}
}
void Spaceship::collide(int objectID)
{
if(objectID == ENEMY)
lives--;
}
Upvotes: 32
Views: 151538
Reputation: 7165
In my case I got error message one or more multiply defined symbols found
, and I find another error message shows xxx function is already defined in ooo.dll
, but in my project doensn't reference ooo.dll
at all.
Then I recall I use vcpkg
to install ooo.dll
possibly globally before, so use vcpkg
to remove uninstall ooo.dll package
, and build again, the error is solved and build success.
Upvotes: 2
Reputation: 4215
I answered a similar question here.
In the Project’s Settings, add /FORCE:MULTIPLE
to the Linker’s Command Line options.
From MSDN: "Use /FORCE:MULTIPLE to create an output file whether or not LINK finds more than one definition for a symbol."
That's what programmers call a "quick and dirty" solution, but sometimes you just want the build to be completed and get to the bottom of the problem later, so that's kind of a ad-hoc solution. To actually avoid this error, provided that you want
int WIDTH = 1024;
int HEIGHT = 800;
to be shared among several source files, just declare them only in a single .c / .cpp file, and refer to them in a header file:
extern int WIDTH;
extern int HEIGHT;
Then include the header in any other source file you wish these global variables to be available.
Upvotes: 3
Reputation: 743
just add /FORCE as linker flag and you're all set.
for instance, if you're working on CMakeLists.txt. Then add following line:
SET(CMAKE_EXE_LINKER_FLAGS "/FORCE")
Upvotes: 0
Reputation: 171097
The two int
variables are defined in the header file. This means that every source file which includes the header will contain their definition (header inclusion is purely textual). The of course leads to multiple definition errors.
You have several options to fix this.
Make the variables static
(static int WIDTH = 1024;
). They will still exist in each source file, but their definitions will not be visible outside of the source file.
Turn their definitions into declarations by using extern
(extern int WIDTH;
) and put the definition into one source file: int WIDTH = 1024;
.
Probably the best option: make the variables const
(const int WIDTH = 1024;
). This makes them static
implicitly, and also allows them to be used as compile-time constants, allowing the compiler to use their value directly instead of issuing code to read it from the variable etc.
Upvotes: 74
Reputation: 409136
You can't put variable definitions in header files, as these will then be a part of all source file you include the header into.
The #pragma once
is just to protect against multiple inclusions in the same source file, not against multiple inclusions in multiple source files.
You could declare the variables as extern
in the header file, and then define them in a single source file. Or you could declare the variables as const
in the header file and then the compiler and linker will manage it.
Upvotes: 6