【问题标题】:Avoid multiple definitions of headers避免标题的多个定义
【发布时间】:2015-05-21 16:46:50
【问题描述】:

我花了大约 2 天的时间研究以避免某些数组的多重定义,我发现了 #ifdef 和 bla bla。所以我尝试用#ifdef 测试我的程序,但它什么也没做,调试器仍然说有多个定义。我的程序是这样工作的。

当然有多个定义,但我需要像我在图片中展示的那样做这个......我认为这是编译器问题或与编译器相关的问题。

PD:我想你不需要任何代码来解决我的问题,如果你需要,我会分享。

GameObject.h:

#ifndef GameObject_H
#define GameObject_H

#pragma once

float cube[] =
{
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f, 1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f,-1.0f, 1.0f,
    1.0f,-1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f,-1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f,-1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f,-1.0f, 1.0f
};

float Space3D_X[] =
{
    0.0f, 0.0f, -100,
    0.0f, 0.0f, 100
};

float Space3D_Z[] =
{
    -100.0f, 0.0f, 0.0f,
    100.0f, 0.0f, 0.0f
};

float Space3D_Y[] =
{
    0.0f, -100.0f, 0.0f,
    0.0f, 100.0f, 0.0f
};

typedef struct GameObject
{
    int ID, parent;
    Vector3 position;
    Quaternion rotation;
};

struct GameObject GameObjects[65536];

typedef struct Entity
{
    static int GameObjectsCount;
    int CreateCube (Vector3 _position, Quaternion _rotation, int _parent);
    void SetGameObjectParent (int _gameObject, int _parent);
};

Entity Entity_t;

#endif // GAMEOBJECT_H

【问题讨论】:

  • 不要将定义放入头文件中。
  • 通常的方法是用ifndef检查给定的token是否被定义,然后定义它,编写所有代码并以endif结束。
  • 我告诉过你我已经这样做了,但还是要检查代码。
  • 回复@KerrekSB 的评论,不要将定义放入头文件中。 Kerrek 的意思是,不要将定义放入头文件中。您的float cube[] = ... 是一个定义。不要在头文件中这样做。这会带来很多麻烦。

标签: c++ header


【解决方案1】:

将定义放入 cpp 文件中。如果你把它们放在头文件中,它们将在每个包含头文件的 cpp 文件中定义。

GameObject.h

#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

extern float cube[];
...
typedef struct GameObject
{
    int ID, parent;
    Vector3 position;
    Quaternion rotation;
};

extern GameObject GameObjects[65536];
...
#endif

游戏对象.cpp

#include "GameObject.h"

float cube[] = {...};
...
GameObject GameObjects[65536];

【讨论】:

    【解决方案2】:

    标头保护仅处理在一个单个翻译单元中多次包含标头(直接或间接)。

    例如,给定 typedef x y; 之类的内容,您不能在同一范围内再次重复相同的 typedef

    typedef x y; // fine
    typedef x y; // Not allowed -- `y` is already defined
    

    多次包含同一个标头(通常不是直接包含两者)可能会导致此类问题,而这正是标头保护所防止的。

    标头保护对因在多个源文件中包含相同标头而产生的任何事情都没有帮助。最明显的例子是当你在头文件中定义了一个对象。然后,当您链接多个包含该标头的源文件时,您最终会出现来自该对象的多个定义的链接错误。

    解决此问题的方法是编写代码,使该对象的定义 在一个源文件中只出现一次。然后,标头仅包含该对象的 声明。例如:

    source.cpp:

    int x[1234];
    

    source.h:

    extern int x[];
    

    这使得x可见,所以其他源文件中的代码可以访问 x,但只在一处定义,所以你不违反一个定义规则,导致链接器抱怨多个定义。

    【讨论】:

    • 这是一个很好的答案,但它让我对 OP 的用例感到好奇——他们想让立方体坐标的这个定义可用于多个不同的代码位——也许它是一个边界框敌人碰撞检测和与地面相交的角色都使用的定义 - 我只是为了说明我的问题而编造这个:你如何处理这些可用于多个可能不相关的代码位的共享定义还是课程?
    • @TomAuger:大约如答案所示。您将创建一个定义类型并声明对象的标题,例如:using Plane = /* however you want to define a plane */; extern Plane ground;,然后是包含该标题的单个 .cpp 文件,并定义地面平面:#include "ground.h"\nPlane ground { /* initializers here */ };,并包含该标题在需要引用地面的任何其他文件中(以及在构建、编译和链接该 .cpp 文件以及其余文件时)。
    猜你喜欢
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多