在课堂上:
class foo
{
public:
static int bar; //declaration of static data member
};
int foo::bar = 0; //definition of data member
我们必须明确定义静态变量,否则会产生
undefined reference to 'foo::bar'
我的问题是:
请注意,这是不与之前提到的undefined reference to static variable
问题的重复。这个问题打算询问静态变量的明确定义背后的原因。
答案 0 :(得分:22)
从一开始,C ++语言就像C一样,建立在独立翻译的原则之上。每个翻译单元由编译器本身独立编译,不需要任何其他翻译单元的知识。整个程序后来才会在连接阶段汇集在一起。链接阶段是链接器看到整个程序的最早阶段(它被视为编译器正确编写的目标文件集合 )。
为了支持独立翻译的这一原则,每个具有外部链接的实体必须在一个翻译单元中定义,并且只在一个翻译单元中定义。用户负责在不同的翻译单元之间分发这些实体。它被认为是用户意图的一部分,即用户应该决定哪个翻译单元(和目标文件)将包含每个定义。
同样适用于该类的静态成员。该类的静态成员是具有外部链接的实体。编译器希望您在某个翻译单元中定义该实体。此功能的全部目的是让您有机会选择该翻译单元。编译器无法为您选择它。这又是你意图的一部分,你必须告诉编译器。
这不再像过去那样重要,因为该语言现在设计用于处理(并消除)大量相同的定义(模板,内联函数等),但是一个定义规则仍然源于独立翻译的原则。
除了上述内容之外,在C ++语言中,您定义变量的点将确定其初始化顺序与相同转换单元中定义的其他变量的关系。这也是用户意图的一部分,即编译器在没有您帮助的情况下无法决定的事情。
答案 1 :(得分:3)
在早期的C ++中,允许在类中定义static
数据成员,这肯定违反了类只是一个蓝图并且没有将内存放在一边的想法。这已经被删除了。
将static
成员的定义放在类之外强调内存只为static
数据成员分配一次(在编译时)。该类的每个对象都没有自己的副本。
答案 2 :(得分:1)
static
是一种存储类型,当你声明变量时,你告诉编译器“本周在某个地方的数据部分”,当你随后使用它时,编译器发出的代码加载来自a的值待定地址。
在某些情况下,编译器可以驱动静态实际上是编译时常量并将其替换为例如
static const int meaning = 42;
在一个永远不会取值的地址的函数中。
但是,在处理类成员时,编译器无法猜测应该在何处创建该值。它可能位于您将链接的库中,或者是一个dll,或者您可能提供了一个库,其中值必须由库使用者提供。
通常,当有人问这个时,是因为他们滥用静态成员。
如果您只想要我们一个恒定值,例如
static int MaxEntries;
...
int Foo::MaxEntries = 10;
使用以下一个或另一个
会更好static const int MaxEntries = 10;
// or
enum { MaxEntries = 10 };
静态不需要单独的定义,直到某些东西试图获取变量的地址或形成对变量的引用,枚举版本永远不会。
答案 3 :(得分:0)
在类中,您只声明变量,即:您告诉编译器存在具有此名称的内容。 但是,静态变量必须占用一些内存空间,并且必须位于一个转换单元内。只有在您定义变量时,编译器才会保留此空间。
答案 4 :(得分:0)
结构不是变量,但它的实例是。因此,我们可以在多个模块中包含相同的结构声明,但我们不能在多个模块中全局定义相同的实例名称。
结构的静态变量本质上是一个全局变量。如果我们在结构声明本身中定义它,我们就不能在多个模块中使用结构声明。因为这将导致在多个模块中定义相同的全局实例名称(静态变量)导致链接器错误"相同符号的多个定义"