我正在运行一个类似于我发现的here的简单程序。这意味着在多个文件中包含常量时减少代码膨胀。它通过在命名空间中使用const全局变量及其各自的extern
前向声明来实现此目的。
globals.h
#ifndef GLOBALS_H_
#define GLOBALS_H_
namespace Constants
{
// forward declarations only
extern const double pi;
extern const double avogadro;
extern const double my_gravity;
}
#endif
globals.cpp
namespace Constants
{
// actual global variables
extern const double pi(3.14159);
extern const double avogadro(6.0221413e23);
extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}
source.cpp
#include <iostream>
#include <limits>
#include "globals.h"
int main()
{
double value_of_pi = Constants::pi;
std::cout << value_of_pi;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
return 0;
}
我假设Constants :: pi获取globals.cpp Constants命名空间中包含的值pi,并且能够这样做,因为它可以从包含的globals.h访问命名空间本身。我不明白为什么globals.cpp中的const全局定义/初始化需要extern
关键字?我尝试删除globals.cpp中的extern
关键字,认为它不需要,但我的程序不会在没有它们的情况下运行。我以为extern
只用于前言声明?为什么const全局定义/初始化需要它们?它与定义的命名空间有关吗?
这意味着在多个文件中包含常量时减少代码膨胀
我建议不要专注于这种优化,除非它变得非常必要,而是选择最简单的设计:直接在头文件中定义这些常量,并包含来自所有需要的翻译单元(“.cpp文件”)的头文件访问这些常量。由于这些对象是const
,它们将具有内部链接,并且链接器不会因违反单一定义规则而尖叫。
我尝试删除globals.cpp中的extern关键字,认为它不需要,但我的程序不会在没有它们的情况下运行
这是因为具有静态存储持续时间的命名空间范围const
对象(如pi
变量)具有内部链接,除非您明确将它们定义为extern
。
我以为extern只用于前言声明?
extern
用于声明在另一个翻译单元(“.cpp文件”)中定义的变量。如果对象是const
,则定义它的翻译单元需要明确地将其标记为extern
,以便它具有外部链接并且可以从其他翻译单元看到(如果对象不是const
则不需要)。
它与定义的命名空间有关吗?
不,这是具有静态存储持续时间的所有命名空间级别const
对象的规则,并且在C ++标准的[basic.link] / 3段中指定:
具有命名空间作用域(3.3.6)的名称具有内部链接(如果它的名称)
(3.1)[...] - 显式声明为静态的变量,函数或函数模板;要么,
(3.2) - 非易失性const限定类型的变量,既未明确声明为extern,也未声明为具有外部链接;要么
(3.3) - 匿名工会的数据成员。