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

时间:2012-07-13 20:49:38

标签: c++ static namespaces

我认为我对名称空间和/或静态变量存在根本性的误解。但我尝试过这个测试代码(手工输入,原谅错别字)

test.h:

namespace test{
   static int testNum=5;
   void setNum(int value);
}

main.cpp中:

#include <test.h>

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

int main(){
    test::setNum(9);
    cout<<test::testNum;
}

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

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

谢谢

3 个答案:

答案 0 :(得分:21)

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

我还假设您有另一个文件,可能名为test.cpp,其中还包含test.h并定义了setNum函数。

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

因此,如果标头中的变量为testNum,那么在包含static的每个文件中都会有一个名为testNum不同的变量。这意味着如果您在一个文件中设置test.h并在使用testNum的其他文件中调用某个函数,则它会引用一个不同的变量,该变量恰好具有相同的名称

因此,在标题中声明非常量testNum变量几乎总是错误的。

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

extern

这告诉编译器有一个名为extern int testNum; // N.B. no "= 1" here 的带有“外部链接”的变量,所以当代码引用testNum时,它总是意味着同一个变量(不是内部linakge的某个名称是每个文件中都有不同的实体。)在声明testNum变量后,您有责任确保程序中某处提供了一个定义,因此在恰好一个文件中(即不在包含在多个文件中的标题)您定义它:

extern

答案 1 :(得分:6)

命名空间范围内的

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

命名空间范围内的

static也已弃用。不要使用它。

关于在标头中声明变量:为它添加前缀 extern,而非static。如果变量声明为extern,则 没有初始化,声明不是定义。的 当然,在这种情况下,你必须在某处提供一个定义(在一个 单源文件)。有点像:

extern int testNum = 5;
int testNum = 5;
int testNum;          //  implicitly initialized with 0.

编辑:

在某种程度上澄清一下:生命与生命之间存在一些混淆 名称绑定:

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

将关键字static与静态生命周期混淆。 (功能 可以是static,但函数在C ++中没有定义的生命周期;他们是 就在那里。)

关于这些的规则不是非常正统的。基本上,与 关于终生:

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

具有静态生命周期的对象在main之前的某个时间出现,并且 从main返回后一直存在。

关于名称绑定:

  • 在命名空间范围内声明的变量具有外部名称绑定, 除非他们被宣布为static,在这种情况下他们有内部 名称绑定(但不推荐使用static),如果是的话 const,并且未声明为extern
  • 在类范围内声明的变量具有外部名称绑定,即使它们被声明为static
  • 在块范围内声明的变量没有绑定。

最后,还有一个问题,即声明是否是一个定义 或不。如果是定义,则分配内存并且对象是 (或可能)初始化。如果它不是一个定义,它只是告诉 编译器,该实体的其他地方有一个定义 声明中声明的(对象)。一般来说,一个变量 声明是的定义,除非声明extern并且确实如此 有初始化程序。

答案 2 :(得分:1)

您可能希望确保您的代码在发布之前确实存在问题,然后询问出错了什么;)

我复制/粘贴并修复了拼写错误,并手动执行了包含:

#include <iostream>
using namespace std;

namespace test{
   static int testNum=5;
   void setNum(int value);
}

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

int main(){
    test::setNum(9);
    cout<<test::testNum;
}

结果:

$ ./a.out 
9

你还没说的是你的课程还有什么。如果你不仅仅是main.cpp,并且包含你的test.h,那么每个.cpp文件都有自己的testNum副本。如果您希望他们分享,那么除了一个之外,您只需将其标记为extern