Fatale fout LNK1169: een of meerdere vermenigvuldige gedefinieerde symbolen gevonden in game-programmering

Ik heb een training om object georiënteerde programmering in C++ te gebruiken, maar ik krijg deze foutmelding:

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

Het lijkt er echter op dat de hele code correct is geschreven en de twee inten worden alleen vermeld in de wereldwijde kop en alle objecten lijken op de juiste manier te vatten. Maar zoals ik zojuist zei, ik ben een beginner in OOP, dus ik heb echt een mening nodig: het is ook de moeite waard om te vermelden dat ik Allegro 5 gebruik om een ​​zijschutter te maken.

Dit is de code:

(hoofd):

#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--;
    }

Antwoord 1, Autoriteit 100%

De twee intvariabelen zijn gedefinieerd in het koptekstbestand. Dit betekent dat elk bronbestand dat de koptekst omvat, hun definitie zal bevatten (header-inclusie is puur tekstueel). De natuurlijk leidt tot meerdere definitiefouten.

U hebt verschillende opties om dit te verhelpen.

  1. Maak de variabelen static(static int WIDTH = 1024;). Ze zullen nog steeds in elk bronbestand bestaan, maar hun definities zijn niet zichtbaar buiten het bronbestand.

  2. Draai hun definities in declaraties door extern(extern int WIDTH;) te gebruiken en de definitie in One Bronbestand: int WIDTH = 1024;.

  3. Waarschijnlijk de beste optie: maak de variabelen const(const int WIDTH = 1024;). Dit maakt ze impliciet staticen maakt het ook mogelijk ze te gebruiken als constanten tijdens het compileren, waardoor de compiler hun waarde rechtstreeks kan gebruiken in plaats van code uit te geven om deze uit de variabele te lezen, enz.


Antwoord 2, autoriteit 10%

Je kunt geen variabeledefinities in header-bestanden plaatsen, omdat deze dan deel uitmaken van alle bronbestanden waarin je de header opneemt.

De #pragma onceis alleen bedoeld om te beschermen tegen meerdere opnames in hetzelfde bronbestand, niet tegen meerdere opnames in meerdere bronbestanden.

U kunt de variabelen declarerenals externin het headerbestand en ze vervolgens definiërenin een enkel bronbestand. Ofu kunt de variabelen declareren als constin het headerbestand en dan zullen de compiler en linker het beheren.


Antwoord 3, autoriteit 2%

const int WIDTH = 1024;
const int HEIGHT = 800;

Antwoord 4

Ik heb hiereen vergelijkbare vraag beantwoord.

Voeg in de Projectinstellingen /FORCE:MULTIPLEtoe aan de Opdrachtregel-opties van de Linker.

Van MSDN: “Gebruik /FORCE:MULTIPLE om een uitvoerbestand te maken, ongeacht of LINK meer dan één definitie vindt voor een symbool.”

Dat is wat programmeurs een “snelle en vuile” oplossing noemen, maar soms wil je gewoon dat de build wordt voltooid en het probleem later wordt opgelost, dus dat is een soort ad-hocoplossing.
Om deze fout daadwerkelijk te voorkomen, op voorwaarde dat u

int WIDTH = 1024;
int HEIGHT = 800;

om te worden gedeeld tussen verschillende bronbestanden, declareer ze alleen in een enkel .c / .cpp-bestand en verwijs ernaar in een headerbestand:

extern int WIDTH;
extern int HEIGHT;

Neem vervolgens de kop op in elk ander bronbestand waarvan u wilt dat deze globale variabelen beschikbaar zijn.


Antwoord 5

In mijn geval kreeg ik een foutmelding one or more multiply defined symbols found, en ik vind dat een andere foutmelding aangeeft dat de xxx function is already defined in ooo.dll, maar in mijn project verwijst helemaal niet naar ooo.dll.

Dan herinner ik me dat ik vcpkggebruik om ooo.dllmogelijk eerder wereldwijd te installeren, dus gebruik vcpkgom de uninstall ooo.dll package, en opnieuw bouwen, de fout is opgelost en succes met bouwen.


Antwoord 6

voeg gewoon /FORCE toe als linkervlag en je bent helemaal klaar.

bijvoorbeeld als u aan CMakeLists.txt werkt. Voeg dan de volgende regel toe:

SET(CMAKE_EXE_LINKER_FLAGS  "/FORCE")

Other episodes