静态常量对命名空间成员有什么影响?

20
// MyClass.h

namespace MyNamespace {

  static const double GasConstant = 1.987;

  class MyClass
  {
    // constructors, methods, etc.
  };
}

之前我在MyClass声明中已经声明了GasConstant(并且由于C++不支持非整数类型的const初始化,所以在源文件中有单独的定义)。但是我需要从其他文件访问它,逻辑上似乎应该在命名空间级别上声明。

我的问题是,在这种情况下,static const有什么影响? 显然,const意味着我不能为GasConstant赋新值,但是命名空间中的静态成员意味着什么。这与文件作用域中的静态相似,其中成员在单元外部无法访问吗?


这是在头文件(.h)中还是在实现文件(.cpp)中? - AnT stands with Russia
3
在C++中没有文件作用域。如果在函数和类外部,只有命名空间作用域。此外,如果您在某些页面上阅读所谓的“全局”,他们通常是指全局命名空间和其他包含的命名空间。例如,cplusplus.com 因其对“全局”一词的不准确使用而闻名。因此,如果某些内容解释了“静态”的“全局作用域”中的效果,它们通常指的是其在命名空间作用域中的影响。 - Johannes Schaub - litb
3个回答

12
在C++中,命名空间范围内使用static已经被弃用。它通常只会出现在源文件中,其作用是使变量局限于该源文件。也就是说,另一个源文件可以有一个完全相同名称的变量而不会冲突。
在C++中,将变量限定在源文件中的推荐方法是使用匿名命名空间。
我认为可以毫不客气地说,在您的代码头文件中使用static是错误的。
*正如Tom在评论中指出的(以及在此answer中),C++委员会撤销了废弃在文件范围内使用static的决定,理由是这种用法将始终是语言的一部分(例如用于C兼容性)。

1
推荐的做法是什么?“这”具体指什么?我不确定我理解得很清楚。 - mindless.panda
1
不再废弃命名空间级别的静态关键字:https://dev59.com/32445IYBdhLWcg3wucio,这使得这个答案不正确,因为现在使用匿名命名空间或静态是实现相同效果的两种被接受和正确的方式。 - Tom
谢谢更新,@Tom - 我会更新答案。 - James Hopkin

4

MSDN 解释如下:

当修改一个变量时,static 关键字指定变量具有静态持续时间(即在程序开始时分配并在程序结束时释放),除非指定其他值,否则将其初始化为 0。 当在文件作用域中修改变量或函数时,static 关键字指定变量或函数具有内部链接(它的名称从声明它的文件外部不可见)。

请记住,包含头文件意味着要用头文件的实际代码替换 "#include" 指令。 因此,静态变量只能在包括这两个头文件的 ".cpp"(被编译的)文件中可见。

因此,每个包含这些头文件的 "cpp" 文件都将拥有自己的静态变量。


现在我已经在Constants.h中声明/定义了GasConstant,并将其包含到MyClass.h中。听起来它只会在包含Constants.h或MyClass.h的文件中可见,而不是从任何其他不包含它的文件中。如果另一个文件同时包含这两个文件会发生什么? - mindless.panda
3
每个.cpp文件都会有自己独立的副本。可能不是你想要的,或者也许正是你想要的。对于同时包含两者的.cpp文件,这不应该改变任何内容,但你当然需要适当的头文件保护。 - Edward Strange
听起来我想做的就是将它设为const。 - mindless.panda

2
如果这是一个头文件,那么在这种情况下 static 是没有影响的。在C++中,const对象默认已经具有内部链接,因此无论您是否使用 static 声明它都没有任何区别。
我猜你只是将声明从类移动到了命名空间中。但是,在类声明的上下文和命名空间的上下文中,static 的含义完全不同。在类内部,您需要使用 static。在命名空间中,static 是多余的。

但是难道不是这样吗?包含头文件的单独文件将由于静态操作类似于文件作用域静态而具有命名空间成员的单独实例。当然,这并不重要,因为它是const,也就是说,如果我认为这两个文件可以访问相同的成员并且从一个文件更新会反映在另一个文件中,那么这将是一个问题。只是想保持清晰明了。 - mindless.panda
1
事实上,在该类中他不需要 static。对于 double,使用和不使用 static 都是无效的 :) - Johannes Schaub - litb
1
实际上这是有影响的。如果在两个翻译单元中实例化Template<GasConstant>,将会违反ODR。 - Martin Bonner supports Monica
C++17 n4659 标准草案 6.5 "程序和链接" - Ciro Santilli OurBigBook.com

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接