常量变量在标题中不起作用
如果我像这样在标题中定义常量变量...
if I define my constant varibles in my header like this...
extern const double PI = 3.1415926535;
extern const double PI_under_180 = 180.0f / PI;
extern const double PI_over_180 = PI/180.0f;
我收到以下错误
1>MyDirectX.obj : error LNK2005: "double const PI" (?PI@@3NB) already defined in main.obj
1>MyDirectX.obj : error LNK2005: "double const PI_under_180" (?PI_under_180@@3NB) already defined in main.obj
1>MyDirectX.obj : error LNK2005: "double const PI_over_180" (?PI_over_180@@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI" (?PI@@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI_under_180" (?PI_under_180@@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI_over_180" (?PI_over_180@@3NB) already defined in main.obj
但是如果我从标题中删除这些常量并将它们放在包含像这样的标题的文档中......
but If I remove those constants from the header and put them in the document that is including the header like this...
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
有效
有没有人知道我可能做错了什么??
Does anyone have Idea what I might be doing wrong ??
谢谢
推荐答案
问题在于您在头文件中定义 具有外部链接的对象.预计,一旦您将该头文件包含到多个翻译单元中,您将获得具有外部链接的同一对象的多个定义,这是一个错误.
The problem is that you define objects with external linkage in header file. Expectedly, once you include that header file into multiple translation units, you'll get multiple definitions of the same object with external linkage, which is an error.
正确的做法取决于您的意图.
The proper way to do it depends on your intent.
您可以将定义放入头文件中,但要确保它们具有内部链接.
在需要显式static
static const double PI = 3.1415926535;
static const double PI_under_180 = 180.0f / PI;
static const double PI_over_180 = PI/180.0f;
在 C++ 中 static
是可选的(因为在 C++ 中 const
对象默认有内部链接)
In C++ static
is optional (because in C++ const
objects have internal linkage by default)
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
或者你也可以只将非定义声明放入头文件中,然后将定义放入一个(并且只有一个)实现文件中
Or you can put mere non-defining declarations into the header file and put the definitions into one (and only one) implementation file
header 文件中的声明必须包含显式的 extern
并且没有初始化器
The declarations in the header file must include an explicit extern
and no initializer
extern const double PI;
extern const double PI_under_180;
extern const double PI_over_180;
和一个实现文件中的定义应如下所示
and definitions in one implementation file should look as follows
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
(定义中的显式 extern
是可选的,如果上述声明位于同一翻译单元中的定义之前).
(explicit extern
in the definitions is optional, if the above declarations precede the definitions in the same translation unit).
您将选择哪种方法取决于您的意图.
Which method you will choose depends on your intent.
第一种方法使编译器更容易优化代码,因为它可以看到每个翻译单元中常量的实际值.但同时在概念上你会在每个翻译单元中获得单独的、独立的常量对象.例如,&PI
将评估为每个翻译单元中的不同地址.
The first method makes it easier for the compiler to optimize the code, since it can see the actual value of the constant in each translation unit. But at the same time conceptually you get separate, independent constant objects in every translation unit. For example, &PI
will evaluate to a different address in each translation unit.
第二种方法创建真正的全局常量,即整个程序共享的唯一常量对象.例如,&PI
将评估为每个翻译单元中的相同地址.但在这种情况下,编译器只能看到一个且只有一个翻译单元中的实际值,这可能会妨碍优化.
The second method creates truly global constants, i.e. unique constant objects that are shared by the entire program. For example, &PI
will evaluate to the same address in each translation unit. But in this case the compiler can only see the actual values in one and only one translation unit, which might impede optimizations.
从 C++17 开始,您将获得第三个选项,它结合了两全其美":内联变量.尽管有外部链接,但内联变量可以安全地定义在头文件中
Starting from C++17 you get the third option, which sort of combines "the best of both worlds": inline variables. Inline variables can be safely defined in header files despite having external linkage
inline extern const double PI = 3.1415926535;
inline extern const double PI_under_180 = 180.0f / PI;
inline extern const double PI_over_180 = PI/180.0f;
在这种情况下,您将获得一个命名常量对象,其初始值设定项在所有翻译单元中都是可见的.同时对象具有外部链接,即它具有全局地址标识(&PI
在所有翻译单元中都相同).
In this case you get a named constant object whose initializer value is visible in all translation units. And at the same time the object has external linkage, i.e. it has a global address identity (&PI
is the same in all translation units).
当然,类似的东西可能只在某些特殊目的下才需要(C++ 中的大多数用例都调用第一个变体),但该功能就在那里.
Granted, something like that might only be necessary for some exotic purposes (most use cases in C++ call for the first variant), but the feature is there.
相关文章