即使使用 ifndef,C++ 重定义错误

c++ redefinition error even with ifndef

本文关键字:定义 错误 C++ ifndef      更新时间:2023-10-16

我有几个文件,我的错误很奇怪。我不知道这是否可能是问题的一部分,我使用OpenGL/SDL,XCode,并使用CMake创建文件。

我有文件Wall.hpp,Wall.cpp,Player.hpp,Player

.cpp,controls.hpp,controls.cpp,main.cpp。

以下是文件包含的摘要:

播放器.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;
};

播放器.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

墙.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

控件.hpp

#ifndef _MACRO_CONTROLS_C
#define _MACRO_CONTROLS_C
#include <vector>
#include "Wall.hpp"
...
#endif

控件.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

主.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"

代码运行良好,直到我将 #include"Wall.hpp"放入文件控件.hpp或/和控件中.cpp。我正面临错误"重新定义墙",以及在此之后"Gl.h 包含在 glew.h 之前"。

我认为问题在于您在controls.cpp中包含标题的方式:

Wall.hpp ->类墙的定义

controls.hpp -> 包括 wall.hpp

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

所以基本上在控件中.cpp你包含了两次类 WALL 的定义者;这可能是你错误的原因。如果您只包含 controls.hpp,您应该摆脱错误

我认为

这里没有足够的信息来准确回答为什么您会看到问题中列出的错误。这可能是由某种递归包含循环引起的,尽管我还没有发现它。

但是,我认为如果您遵循一些基本的C++卫生习惯,这些问题就会消失。

  1. 不要包含 cpp 文件。您应该分别编译其中的每一个,然后使用链接器将它们链接在一起。我不熟悉 XCode,但如果项目设置正确,大多数 IDE 将能够自动执行此操作。使用外部生成文件来处理这些任务也很常见。

    在评论中,您提到当您不包含来自main.cpp的cpp文件时,您遇到了符号解析错误。这很可能意味着我上面提到的链接步骤没有正确完成。

  2. 在每个头文件 (hpp) 中放置包含保护,但不在 cpp 文件中放置(它们不是必需的,因为从步骤 1 开始,您不包括它们)。

  3. 我过去发现很多问题源于不正确的包括警卫。

    最常见的是从一个文件复制/粘贴到另一个文件,而忘记更改宏名称。

    另一个可能发生的情况是,包含树中有多个目录,同名文件位于两个不同的目录中。在这种情况下,您需要在保护宏名称中包含目录名称。

    然而,问题的另一个来源可能是 #if/#endif 对不匹配。在大多数情况下,这是显而易见的,因为预处理器会抱怨,但是如果您有两组不匹配对,那么它可能会产生意外的结果。最好在 #endif 后放置注释以显示它们与哪个警卫相关联,例如:

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

    一些 IDE(例如Eclipse CDT) 将自动以这种格式添加这些守卫。

  4. 不要在保护宏(或任何其他宏)中包含前导下划线,以避免与系统定义的宏发生可能的冲突。

  5. 在每个文件(cpp 或 hpp)中,仅包含定义您在该文件中使用的类、函数、变量等所需的 hpp 文件。

  6. 每个 cpp 文件都应该有一个相应的 hpp 文件,该文件声明了相应 cpp 文件中定义的项目。cpp 文件应包含 hpp 文件。hpp 文件包含的任何内容都不需要由 cpp 文件重新包含。

    许多C++程序员坚持每个类都应该在单独的文件中定义的规则。这不是绝对必要的,但可以更轻松地维护代码。