我读到在源文件中定义静态数据成员的原因是因为如果它们在头文件中并且多个源文件包含头文件 - 定义将多次输出。我明白为什么这对静态 const 数据成员来说是个问题,但为什么这对静态数据成员来说是个问题?
我不太确定我是否完全理解如果定义写在头文件中为什么会出现问题...
最佳答案
变量的多重定义问题是由于语言定义中的两个主要缺陷。
如下所示,您可以轻松解决它。没有直接支持的技术原因。这与委员会成员选择将其作为优先事项的需求不够高有关。
首先,为什么多重定义通常是个问题。由于 C++ 不支持单独编译的模块(缺陷 #1),程序员必须通过使用文本预处理等来模拟该功能。然后很容易无意中引入两个或多个同名定义,这很可能是错误的。
对于函数,这是通过 inline
关键字和属性解决的。独立函数只能显式内联
,而成员函数可以通过在类定义中定义来隐式内联
。无论哪种方式,如果一个函数是 inline
,那么它可以在多个翻译单元中定义,并且它必须在使用它的每个翻译单元中定义,并且这些定义必须是等价的。
主要是该解决方案允许在头文件中定义类。
不需要这样的语言特性来支持数据,头文件中定义的变量,所以它不存在:你不能有 inline
变量。这是语言缺陷#2。
但是,您可以通过对类模板的static
数据成员的特殊豁免来获得内联
变量的效果。豁免的原因是类模板通常必须在头文件中完全定义(除非模板仅在翻译单元内部使用),因此类模板能够具有 static
数据成员,有必要免除一般规则,或一些特殊支持。委员会选择了规则豁免路线。
template< class Dummy >
struct math_
{
static double const pi;
};
template< class Dummy >
double const math_<Dummy>::pi = 3.14;
typedef math_<void> math;
以上被称为模板化常量技巧。据我所知,我曾经在 [comp.lang.c++] Usenet 组中介绍过它,所以我不能相信其他人。我还在 SO 上发布了几次。
无论如何,这意味着每个 C++ 编译器和链接器都在内部支持并且必须支持内联
数据所需的机制,但该语言没有该功能。
但是,在第三方面,C++11 有constexpr
,您可以将上面的代码写成
struct math
{
static double constexpr pi = 3.14;
};
嗯,有一个区别,你不能获取 C++11 math::pi
的地址,但这是一个非常小的限制。
关于c++ - 声明普通类和类模板的静态数据成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15443901/