全局范围vs全局命名空间
我看到了这两个短语的用法:全局范围和全局命名空间。 他们有什么区别?
在C ++中,每个名字的范围都不存在。 范围可以通过多种方式来定义:可以通过名称空间 , 函数 , 类来定义范围。
因此,全局或其他名称空间定义了一个范围。 全局命名空间是指使用::
,并且在这个命名空间中定义的符号被认为具有全局作用域。 默认情况下,符号存在于全局名称空间中,除非它是在块内定义的,以关键字namespace
开头,或者是类的成员或函数的局部variables:
int a; //this a is defined in global namespace //which means, its scope is global. It exists everywhere. namespace N { int a; //it is defined in a non-global namespace called `N` //outside N it doesn't exist. } void f() { int a; //its scope is the function itself. //outside the function, a doesn't exist. { int a; //the curly braces defines this a's scope! } } class A { int a; //its scope is the class itself. //outside A, it doesn't exist. };
还要注意名字可以被名称空间,函数或类定义的内部作用域隐藏。 所以内部命名空间N
的名称a
隐藏全局namspace中的名称a
。 以同样的方式,函数和类中的名称隐藏了全局名称空间中的名称。 如果您遇到这种情况,那么您可以使用::a
引用全局名称空间中定义的名称:
int a = 10; namespace N { int a = 100; void f() { int a = 1000; std::cout << a << std::endl; //prints 1000 std::cout << N::a << std::endl; //prints 100 std::cout << ::a << std::endl; //prints 10 } }
“范围”是比“命名空间”更普遍的术语。 每个名称空间,类和代码块都定义了一个范围,其中可以使用其中声明的名称; 名称空间是在类和函数之外声明的名称的容器。
“全球范围”和“全球名称空间”可以或多或less互换使用; 名称空间中声明的名称范围覆盖整个名称空间。 如果您特别指名称空间,请使用“名称空间”;如果引用名称空间中名称的可见性,请使用“名称空间”。
范围表示对象的生命周期,只要程序执行,就可以拥有一个全局variables,或者只要该代码块执行,就可以拥有一个块范围的variables。 考虑这个例子:
#include <iostream> int a = 100; main () { int a = 200; std::cout << "local a is: " << a << std::endl; std::cout << "global a is: " << ::a << std::endl; return 0; }
当执行语句时,将显示local a is: 200
,这是显而易见的,因为我们正在重新定义a
main
在哪个叶子的范围内的封闭块。 我们还打印global ::a
,它再次打印期望值100,因为我们已经要求全局命名空间::
。
命名空间的语义大多是合乎逻辑的,它是一种隔离符号的方式,希望避免名称冲突,不会影响对象的使用寿命。
另一方面,范围表示一个对象的生命周期,全局a
在本地a
之前就已经存在,因为它被构造得比主要被执行得早得多。 但是,作用域也会在符号上强制使用名称空间,但与namespace
作用方式不同。 有不同types的范围, global
, class
, function
, block
, file
等…
令人困惑的是,范围有时被重载以表示特定符号的可见性,这是从C借用的,命名空间的概念不存在,范围被用来表示寿命和可见性。 然而,在C ++中,规则有所改变,但术语范围仍然以相同的方式使用,因为这两种语言共享大量的概念。
@Dmitriy Ryajov
这个话题有点老,但我想提供我的帮助。 我认为你不应该把事情做得比现实更复杂。 标识符的Scope
是计算机程序的一部分,其中标识符(指代程序中某个实体的名称)可用于查找被引用的实体。 所以术语范围只适用于标识符,我们不应该将其与对象的生命周期相混淆。 他们有点连接,但不应该混淆。 对象的生存期由我们为该对象分配内存的位置来表示。 所以,例如,如果内存分配在堆栈上,只要函数完成,它就会被释放。 所以这取决于我们存储对象的位置,并表示它的生命周期。 范围只说:“这是一个对象的名称,我们可以使用这个名称的对象,直到那时”。 所以,正如我所说的,术语scope
仅仅是对象的标识符,而生命期是另外一种东西,我们在那里存储对象。
另外,关于与此密切相关的linkage
,我想说一下。 这有时也会令人困惑。 假设我们在translation unit
中有一些指向某些对象的标识符。 other
翻译单元中的相同标识符是否指相同的实体由连接表示。 因此,例如,如果标识符具有外部链接,则可以通过使用关键字extern
声明来引用此标识符引用的实体,但是可以引用其他翻译单元。 现在,假设我们不想在其他翻译单元中使用该实体。 然后,实体将一直exist
直到程序结束,但是当我们不声明时,我们将无法引用它。 另外请注意,现在我混合使用术语联系和生命。 但是这是因为只有global
实体有外部联系。 函数中的标识符不能从程序的其他部分引用。
结论:总是尽量保持简单。 我很惊讶不同的人如何谈论这些术语。 单独编译的整个过程是令人困惑的,因为有多个术语几乎有相同的含义,可能大家都会卡在这一点上。
例如,当我声明一个全局variablesint i
,我们说i is in the global namespace
并且has the global namespace scope
。 就这样。
摘自C ++ 03:
3.3.5 Namespace scope The outermost declarative region of a translation unit is also a namespace, called the global namespace. A name declared in the global namespace has global namespace scope (also called global scope).