c++ redefinition error even with ifndef

3k views Asked by At

I have several files, and my error is quite odd. I don't know if it might be part of the problem, I work with OpenGL/SDL, with XCode, and I created the files using CMake.

I have files Wall.hpp, Wall.cpp, Player.hpp, Player.cpp, controls.hpp, controls.cpp, main.cpp.

Here is a summarization of the files inclusions:

// Player.hpp

#include <iostream>


class Player{
    public :
    Player();
    int getLifePoints();
    int getStaminaPoints();
    float getPosX();
    float getPosY();
    float getPosZ();

    void setPosX(float x);
    void setPosY(float y);
    void setPosZ(float z);

    void reducePoints(int damage);
    bool isHeroRunning();
    void changeHeroRun();
    bool isHeroDucking();
    void changeHeroDuck();


    private :
    int lifePoints;
    int staminaPoints;
    float posX;
    float posY;
    float posZ;
    bool isRunning;
    bool isDucking;

};

// Player.cpp

#include "Player.hpp"
using namespace std;

Player::Player(){
    this->lifePoints = 100;
    this->posX = 0;
    this->posY = 0;
    this->posZ = 0;
}

int Player::getLifePoints(){
    return this->lifePoints;
}
int Player::getStaminaPoints(){
    return this->staminaPoints;
}

float Player::getPosX(){
    return this->posX;
};
float Player::getPosY(){
    return this->posY;
};
float Player::getPosZ(){
    return this->posZ;
};

void Player::setPosX(float x){
    this->posX=x;
};
void Player::setPosZ(float z){
    this->posZ=z;
};
void Player::setPosY(float y){
    this->posY=y;
};

void Player::reducePoints(int damage){
    this->lifePoints= lifePoints - damage;
}

int lifePoints;
float posX;
float posY;
float posZ;

bool Player::isHeroRunning(){
    return isRunning;
}

void Player::changeHeroRun(){
    this->isRunning=!this->isRunning;
}

bool Player::isHeroDucking(){
    return this->isDucking;
}
void Player::changeHeroDuck(){
    this->isDucking=!this->isDucking;
    if (isDucking){
        this->posZ=this->posZ/2;
    } else {
        this->posZ=this->posZ*2;
    }
}

// Wall.hpp

#ifndef _WALL_H
#define _WALL_H

#include <iostream>
#include <vector>
// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GL/glfw.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

class Wall{
    public :
    Wall(GLfloat x1, GLfloat x2, GLfloat z1, GLfloat z2);
    //~Wall();
    GLfloat getX1();
    GLfloat getX2();
    GLfloat getY1();
    GLfloat getY2();
    GLfloat getZ1();
    GLfloat getZ2();
    int isInZone(GLfloat x, GLfloat y, GLfloat z);
    std::vector<GLfloat> add_wall (std::vector<GLfloat> walls);


private:
    GLfloat x1, x2, y1, y2, z1, z2;

};

#endif

// Wall.cpp

#ifndef _WALL_C
#define _WALL_C

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GL/glfw.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "Wall.hpp"
#include <vector>

Wall::Wall(GLfloat x1, GLfloat x2, GLfloat z1, GLfloat z2){
    this->x1=x1;
    this->x2=x2;
    this->y1=y_floor;
    this->y2=y_ceiling;
    this->z1=z1;
    this->z2=z2;
}

#endif

// controls.hpp

#ifndef _MACRO_CONTROLS_C
#define _MACRO_CONTROLS_C

#include <vector>

#include "Wall.hpp"
...
#endif

//controls.cpp

#ifndef _MACRO_CONTROLS_C
#define _MACRO_CONTROLS_C


// Include GLFW
#include <GL/glfw.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;

#include <iostream>

#include "controls.hpp"

#include <unistd.h>

#define GetCurrentDir getcwd

#include "Wall.hpp"
...
#endif

//main.cpp

// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <list>
#include <vector>
#include <time.h>
#include <typeinfo>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GL/glfw.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;

#include <unistd.h>
#define GetCurrentDir getcwd

#include <common/shader.hpp>
#include <common/texture.hpp>
#include <common/controls.hpp>
#include "Player.cpp"
#include "Turret.hpp"

#include "Wall.hpp"

The code works well until I put the #include "Wall.hpp" in the files controls.hpp or/and controls.cpp . I am facing the error "redefinition of Wall", and also after this one "Gl.h included before glew.h".

2

There are 2 answers

2
Pandrei On BEST ANSWER

I think the problem is in the way you include the headers in controls.cpp:

Wall.hpp -> definition for class WALL

controls.hpp -> includes wall.hpp

controls.cpp -> includes wall.hpp and controls.hpp

So basically in controls.cpp you include the definitian for class WALL twice; this might be the cause of your error. If you include only controls.hpp, it you should get rid of the error

1
harmic On

I don't think there is enough information here to answer exactly why you are seeing the errors you list in the question. It could be caused by a recursive include cycle of some kind although I have not spotted it yet.

However, I think these problems will disappear if you follow some basic C++ hygiene.

  1. Do not include cpp files. You are supposed to compile each of these separately and then use the linker to link them together. I am not familiar with XCode, but most IDEs will be able to do this automatically if the project is set up correctly. It is also quite common to use an external Makefile to handle these tasks.

    In the comments you mentioned that when you did not include cpp files from main.cpp, you got a symbol resolution error. This most likely means that the linking step I mentioned above is not being done properly.

  2. Put include guards in every header (hpp) file but not in the cpp files (they are not needed since from step 1, you do not include them).

  3. I have found plenty of problems in the past stemming from incorrect include guards.

    The most common one is copy/pasting from one file to another and forgetting to change the macro name.

    Another that can occur is where you have multiple directories in your include tree, with files of the same name in two different directories. In that case you need to include the directory name in the guard macro name.

    Yet another source of problems can be mismatching #if / #endif pairs. In most cases this will be obvious because the pre-processor will complain, but if you had two sets of mismatching pairs then it might even out with unexpected results. It's good practice to place comments after the #endif to show which guard they are associated with, eg:

    #ifndef WALL_H
    #define WALL_H
    
    ...
    
    #endif /* WALL_H */
    

    Some IDEs (eg. Eclipse CDT) will add these guards in this format automatically.

  4. Do not include leading underscores in the guard macros (or any other macros for that matter) to avoid possible clashes with system defined macros.

  5. In each file (cpp or hpp) include only the hpp files needed to define the classes, functions, variables etc that you are using in that file.

  6. Each cpp file should have a corresponding hpp file, which declares the items defined in the corresponding cpp file. The cpp file should include the hpp file. Anything included by the hpp file does not need to be re-included by the cpp file.

    Many C++ programmers insist on the rule that each class should be defined in a separate file. It's not strictly necessary but can make it easier to maintain the code.