C ++中的静态变量


69

我想知道头文件中的静态变量与类中声明的静态变量之间有什么区别。在头文件中声明静态变量时,其范围仅限于.h文件或跨所有单元。同样,通常在类中声明时,静态变量会在.cpp文件中初始化吗?那是否意味着静态变量范围限制为2个编译单元?


10
'static'关键字非常重载。在不同的地方意味着不同。这就是为什么在面试时提出一个有趣的问题的原因。
vrdhn

绝对在顶部,与抽象函数/抽象类以及诸如公共/受保护/私有继承之类的东西一起。;-)
DevSolar 2010年

1
@vrdhn一点也不有趣……
skytree '20

Answers:


98

对不起,当我无序回答您的问题时,这种方式会更容易理解。

在头文件中声明静态变量时,其范围仅限于.h文件或跨所有单元。

没有“头文件范围”之类的东西。头文件包含在源文件中。转换单元是源文件,包括头文件中的文本。无论您在头文件中写入什么内容,都将复制到每个包含源文件的文件中。

这样,在头文件中声明的静态变量就像在每个单独的源文件中的静态变量一样。

由于声明一个变量static这种方式意味着内部连接,每个翻译单元#include荷兰国际集团的头文件中获取自己的单独的变量(不可见之外的翻译单元)。这通常不是您想要的。

我想知道头文件中的静态变量与类中声明的静态变量之间有什么区别。

在类声明中,static表示该类的所有实例都共享该成员变量;也就是说,您可能有数百个这种类型的对象,但是只要这些对象之一引用static(或“类”)变量,则所有对象的值都是相同的。您可以将其视为“全球一流”。

同样,通常在类中声明时,静态变量会在.cpp文件中初始化吗?

是的,一个(只有一个)翻译单元必须初始化class变量。

那是否意味着静态变量范围限于2个编译单元?

就像我说的:

  • 标头不是编译单元,
  • static 取决于上下文,意味着完全不同的事物。

全局static限制范围适用于翻译单位。类static对所有实例均是全局的。

我希望这有帮助。

PS:请检查Chubsdad答案的最后一段,内容是关于您不应该static在C ++中用于指示内部链接而是匿名名称空间的方式。(因为他是对的。;-))


13
“静态意味着根据上下文而完全不同的事物。” ->最令人困惑的地方。这种“不添加关键字”的思维方式确实很烦人:(
Matthieu M.

@Matthieu M.取决于您的立场。为了保持C和C ++之间的兼容性,这是非常有益的。不过,我承认他们与有点过分了static
DevSolar

1
我知道兼容性是必要的,否则该语言就不会那么流行。但是,他们可以为C ++的含义使用新的关键字,可以使它在类/结构范围之外成为“非关键字”,以保持向后兼容性。我很高兴他们确实nullptr在C ++ 0x中引入了关键字。
Matthieu M.

1
好吧……static在类作用域中用法与在函数作用域中的用法(在多个用途中保持不变的变量)有点相似。他们确实介绍了一种摆脱static(匿名命名空间)的另一种用法的方法……总而言之,这项工作还不错。在任何情况下,它都比Java更好。:-D
DevSolar

54

头文件中的静态变量:

'common.h'

static int zzz;

该变量'zzz'具有内部链接(在其他翻译单元中不能访问该相同变量)。每个包含的翻译单元'common.h'都有其自己的唯一name对象'zzz'

类中的静态变量:

类中的静态变量不是该类的子对象的一部分。该类的所有对象共享一个静态数据成员的副本。

$ 9.4.2 / 6-“在命名空间范围内的类的静态数据成员具有外部链接(3.5)。本地类不应具有静态数据成员。”

所以说'myclass.h'

struct myclass{
   static int zzz;        // this is only a declaration
};

并且myclass.cpp

#include "myclass.h"

int myclass::zzz = 0           // this is a definition, 
                               // should be done once and only once

并且"hisclass.cpp"

#include "myclass.h"

void f(){myclass::zzz = 2;}    // myclass::zzz is always the same in any 
                               // translation unit

并且"ourclass.cpp"

#include "myclass.h"
void g(){myclass::zzz = 2;}    // myclass::zzz is always the same in any 
                               // translation unit

因此,类静态成员不仅限于2个翻译单元。在任何一个翻译单元中只需定义一次即可。

注意:不建议使用'static'声明文件作用域变量,而未命名的命名空间是更好的选择


1
看到头文件可以包含其他头文件,因此“其中的每个文件” ...都是不精确的。最好坚持使用短语编译单元翻译单元
Ben Voigt 2010年

3
和+1指出匿名名称空间会取代static全局变量的修饰符。
Ben Voigt

@Ben Voight:是的,我将其更改为翻译单位。旧习惯难改...谢谢
Chubsdad 2010年

14

在类之外的头文件中声明的静态变量将file-scoped在每个包含头的.c文件中。这意味着可以在包含头文件的每个.c文件中访问具有相同名称的变量的单独副本。

另一方面,静态类变量是,class-scoped并且对于每个编译单元(包括包含带有静态变量的类的头)的编译单元,都可以使用相同的静态变量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.