【问题标题】:Why include guards gives no effect for me? Am I missing something?为什么包括警卫对我没有影响?我错过了什么吗?
【发布时间】:2013-08-12 22:03:35
【问题描述】:

MainGame.h

#ifndef MainGame_h
#define MainGame_h

#include <string>
#include <sstream>
#include "Horde3D.h"

//definitions

#endif MainGame_h

MainGame.cpp

#include <math.h>
#include <iomanip>
#include "Horde3DUtils.h"
#include "MainGame.h"
#include "GameConfig.h" //<--

//code

main.cpp

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>

#include "glfw.h"
#include "MainGame.h"
#include "GameConfig.h" //<--

//code

GameConfig.h

#ifndef GameConfig_h
#define GameConfig_h

#include <string>
#include <sstream>

#define MAX_PATH 260

class GameConfig
{
    static std::string ExtractStartupPath(char *full_app_path)
    {
        const std::string s(full_app_path);

        if(s.find( "/" ) != std::string::npos)
            return s.substr( 0, s.rfind( "/" )) + "/";
        else if(s.find( "\\" ) != std::string::npos )
            return s.substr( 0, s.rfind( "\\" )) + "\\";
        else
            return "";
    }

public:
    static bool IsFullScreen;
    static int StatMode;
    static int FreezeMode;
    static bool DebugViewMode;
    static bool WireframeMode;
    static char *GameTitle;
    static int WindowWidth, WindowHeight;
    static char StartupPath[MAX_PATH];
    static char ContentPath[MAX_PATH];

    static void Initialize(char *startup_path)
    {
        GameTitle = "TestGame\0";

        std::string startup_dir = ExtractStartupPath(startup_path);
        memcpy(StartupPath, startup_dir.c_str(), startup_dir.length() * sizeof(char));

        std::string path(StartupPath);
        path.erase(path.find_last_of('\\'), std::string::npos);
        path.append("\\Content");
        memcpy(ContentPath, path.c_str(), path.length() * sizeof(char));
    }
};

int GameConfig::StatMode = 0;
int GameConfig::FreezeMode = 0;
bool GameConfig::DebugViewMode = false;
bool GameConfig::WireframeMode = false;
bool GameConfig::IsFullScreen = false;
int GameConfig::WindowWidth = 800;
int GameConfig::WindowHeight = 600;
char GameConfig::StartupPath[MAX_PATH] = { 0 };
char GameConfig::ContentPath[MAX_PATH] = { 0 };
char *GameConfig::GameTitle = "TestGame\0";

#endif GameConfig_h

编译时出现链接器错误...

main.obj : error LNK2005: "public: static int GameConfig::StatMode" (?StatMode@GameConfig@@2HA) is already define in в MainGame.obj

但我不明白为什么... GameConfig 只有两个包含 - 一个在 MainGame.cpp 中,第二个在 ma​​in.cpp 中。那些不应该越过。就算他们穿越了,那#ifndef GameConfig_h#define GameConfig_h#endif GameConfig又是为了什么?

我使用的是 VC++ 2010 速成版

【问题讨论】:

  • 能否将GameConfig类的定义添加到GameConfig.h中的sn-p中?
  • 完成。查看更新后的问题。
  • 感谢所有回答的人。

标签: c++ include-guards


【解决方案1】:

包含保护可帮助您避免多次包含来自同一个翻译单元的同一个文件。但是,由于翻译单元是独立处理的,它们都会得到包含的代码,因此会产生重复的定义。

为避免此问题,您需要将定义从标题中移出并放入 CPP 文件中:

GameConfig.cpp:

#include "GameConfig.h"

int GameConfig::StatMode = 0;
int GameConfig::FreezeMode = 0;
bool GameConfig::DebugViewMode = false;
bool GameConfig::WireframeMode = false;
bool GameConfig::IsFullScreen = false;
int GameConfig::WindowWidth = 800;
int GameConfig::WindowHeight = 600;
char GameConfig::StartupPath[MAX_PATH] = { 0 };
char GameConfig::ContentPath[MAX_PATH] = { 0 };
char *GameConfig::GameTitle = "TestGame\0";

【讨论】:

    【解决方案2】:

    您需要将静态的初始化移至 GameConfig.cpp。

    目前每个包含 GameConfig.h 的源文件都在获取它们自己的这些变量的副本。

    【讨论】:

      【解决方案3】:

      您的静态成员的实例不应在 .h 文件中,而应在相应的 .cc 文件中。

      否则它们会在每个编译单元中实例化。

      【讨论】:

        【解决方案4】:

        包含保护仅在单个编译单元中有用(即单个 cpp 文件)。由于 cpp 文件是单独编译的,因此对于每个文件,include 保护将以未定义的形式开始,因此 .h 文件将被包含两次,每个 cpp 文件一次。如果 .h 文件包含例如函数定义,它将被定义两次。

        通常,您只需在 h 文件中放置声明,并在 cpp 文件中实际定义函数,即可使问题“消失”。这样,函数只会被定义一次。

        【讨论】:

          猜你喜欢
          • 2016-04-13
          • 1970-01-01
          • 2011-07-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-17
          • 2017-01-26
          相关资源
          最近更新 更多