我认为我对名称空间和/或静态变量存在根本性的误解。但我尝试过这个测试代码(手工输入,原谅错别字)
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被声明为多次,有人可以解释为什么会这样吗?
谢谢
答案 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
。