如何在命名空间中使用变量

dso*_*len 11 c++ static namespaces

我认为我对命名空间和/或静态变量有一个根本的误解.但我试过这个测试代码(手工输入,原谅错别字)

test.h:

namespace test{
   static int testNum=5;
   void setNum(int value);
}
Run Code Online (Sandbox Code Playgroud)

main.cpp中:

#include <test.h>

int test::setNum(int value){
   testNum=value;
}

int main(){
    test::setNum(9);
    cout<<test::testNum;
}
Run Code Online (Sandbox Code Playgroud)

当我运行这个时,我得到的值是5,而不是我预期的9.看起来好像我有两个testNum变量的实例,但这似乎与静态应该做的完全相反.我猜我错误地认为这些功能与他们的java equovilants在某种程度上相同......

我还得到一个错误,指出如果我从testNum的声明中删除静态,则testNum被声明为多次,有人可以解释为什么会这样吗?

谢谢

Jon*_*ely 22

首先,你的误解与命名空间无关,它只是关于static.对于本答案的其余部分,我将简单地提及testNum它在命名空间中的事实是无关紧要的.

我还假设你有另一个文件,可能叫做test.cpp,它还包括test.h并定义了这个setNum函数.

当声明名称空间范围内的变量或函数(即不是类成员或函数的本地成员)时,static它意味着实体的名称是该文件的内部名称.它正式具有"内部链接",这意味着它不能通过名称引用或链接到其他文件(它可以间接通过指针引用或通过将其作为参数传递给另一个函数.)这意味着如果有几个文件定义static int testNum然后每个文件都有自己的内部变量,该变量具有该名称,与testNum其他文件不同(事实上,一个文件可以有static int testnum另一个文件,另一个文件可以有static double testnum另一个static char* testNum,它们都是不同的,每个文件都是内部的.)如果你在标题中放置这样的定义,然后包含标题的每个文件都有自己的定义testNum.

因此,static对于标题中的变量,您可以在包含的每个文件中调用另一个变量.这意味着如果您在一个文件中设置并在另一个使用它的文件中调用一个函数,则会引用另一个变量,该变量恰好具有相同的名称.testNumtest.htestNumtestNum

因此,static在头文件中声明非const 变量几乎总是错误的.

如果没有static你将testNum在每个包含的文件中定义变量test.h,这是不允许的:每个实体必须只在程序中定义一次和一次.解决这个问题的方法是在头文件中声明变量,但不要定义它,你可以通过告诉编译器变量是extern:

extern int testNum;  // N.B. no "= 1" here
Run Code Online (Sandbox Code Playgroud)

这告诉编译器有一个带有"外部链接"的变量被调用testNum,所以当代码引用testNum时它将始终意味着相同的变量(不是某个名称与内部linakge在每个文件中是不同的实体.)声明extern变量后它是你有责任确保在程序中的某个地方只提供一个定义,所以在一个文件中(即不在包含在多个文件中的标题中)你定义它:

int testNum = 1;
Run Code Online (Sandbox Code Playgroud)


Jam*_*nze 6

static在命名空间范围是用词不当,不应该使用.它简单地表示声明为static的实体具有内部名称绑定; 换句话说,其他翻译单元中的相同名称将引用不同的实体,并且在变量定义的情况下,每个翻译单元中将存在单独的变量实例.它对生命没有影响.(在命名空间范围内声明或定义的所有变量都具有静态生存期.

static在命名空间范围也不推荐使用.不要使用它.

关于在标头中声明变量:使用前缀extern,而不是前缀 static.如果声明了变量extern,并且没有初始化,则声明不是定义.当然,在这种情况下,您必须在某处(在单个源文件中)提供定义.有点像:

extern int testNum = 5;
int testNum = 5;
int testNum;          //  implicitly initialized with 0.
Run Code Online (Sandbox Code Playgroud)

编辑:

为了澄清一点:在生命周期和名称绑定之间存在一些混淆:

  • 对象具有生命周期(自动,静态或动态或临时或异常),以及
  • 名称与实体绑定; 如果名称声明为变量,则实体是对象.

千万不能混淆的关键词static静态寿命.(函数可以static,但函数在C++中没有定义的生命周期;它们就在那里.)

关于这些的规则不是非常正统的.基本上,关于寿命:

  • 在命名空间范围内声明的所有变量都具有静态生命周期
  • 在本地范围内声明的变量具有自动生存期,除非它们被声明static,并且
  • 在类范围内声明的变量具有包含它们的类对象的生命周期,除非它们被声明static.关于终生.

具有静态寿命的物体在之前的某个时间出现main,并且在您返回之后一直存在main.

关于名称绑定:

  • 在命名空间范围内声明的变量具有外部名称绑定,除非它们被声明static,在这种情况下它们具有内部名称绑定(但是这种使用已static被弃用),或者如果它们是 const,并且未声明extern,
  • 在类范围内声明的变量具有外部名称绑定,即使它们已声明static,也是如此
  • 在块作用域中声明的变量没有绑定.

最后,还有一个问题,即声明是否是一个定义.如果是定义,则分配内存并且(或可以)初始化对象.如果它不是定义,它只是告诉编译器在声明中声明的实体(对象)的其他地方有一个定义.一般情况下,一个变量声明是一个定义,除非它被声明extern并没有 有初始值.