我看到了这两个短语的用法:全局作用域和全局命名空间。它们之间有什么区别?
5 回答
在 C++ 中,每个名称都有其不存在的范围。范围可以通过多种方式定义:它可以通过命名空间、函数、 类和{}来定义。
所以一个命名空间,无论是全局的还是其他的,都定义了一个范围。全局命名空间指的是 using ::
,并且在这个命名空间中定义的符号被称为具有全局范围。默认情况下,符号存在于全局命名空间中,除非它是在以关键字开头的块内定义的namespace
,或者它是类的成员,或者是函数的局部变量:
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.
};
另请注意,名称可以被命名空间、函数或类定义的内部范围隐藏。因此a
命名空间内的名称N
隐藏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
}
}
例如,当您声明一个全局变量int i
时,我们说i is in the global namespace
and 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).
“作用域”是比“命名空间”更笼统的术语。每个命名空间、类和代码块都定义了一个作用域,其中声明的名称可以在其中使用;命名空间是在类和函数之外声明的名称的容器。
“全局范围”和“全局命名空间”可以或多或少互换使用;在命名空间中声明的名称的范围涵盖整个命名空间。如果您具体指的是命名空间,请使用“命名空间”,如果您指的是其中名称的可见性,请使用“范围”。
范围表示对象的生命周期,您可以拥有一个只要程序执行就存在的全局变量,或者您可以拥有一个具有块范围的变量,只要该代码块执行就存在。考虑这个例子:
#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,因为我们已经请求了 global namespace ::
。
命名空间语义大多是合乎逻辑的,它是一种将符号彼此隔离的方式,希望避免名称冲突,它不会影响对象的生命周期。
另一方面,范围表示对象的生命周期,全局a
在局部之前出现,a
因为它的构造比 main 执行要早得多。但是,作用域也会在符号上强制使用名称空间,但与 a 的方式不同namespace
。有不同种类的范围,global
, class
, function
, block
,file
等等...
令人困惑的部分是作用域有时被重载以表示特定符号的可见性,这是从 C 中借来的东西,其中不存在命名空间的概念,而作用域被用来表示寿命和可见性。然而,在 C++ 中,规则发生了一些变化,但术语作用域仍然以相同的方式使用,因为这两种语言有很多概念。
@Dmitriy Ryajov
这个话题有点老了,但我想就此提供帮助。我认为你不应该让事情变得比实际情况更复杂。Scope
标识符的名称是计算机程序的一部分,其中标识符(指代程序中某个实体的名称)可用于查找所引用的实体。因此,术语范围仅适用于标识符,我们不应将其与对象的生命周期混为一谈。它们有些联系,但不应混淆。对象的生命周期由我们为该对象分配内存的位置表示。因此,例如,如果在堆栈上分配了内存,它将在函数完成后立即释放。所以这取决于我们存储对象的位置,这表示它的生命周期。范围仅说:“这是一个对象的名称,我们可以在此之前为该对象使用此名称”。所以,正如我所说,这个词scope
仅用于对象的标识符,生命周期是其他东西,由我们存储对象的位置表示。
另外,我想说一些linkage
与此密切相关的事情。这有时也可能令人困惑。假设我们有一些标识符translation unit
引用一些对象。翻译单元中的相同标识符是否other
将引用相同的实体由链接表示。因此,例如,如果标识符具有外部链接,我们可以通过使用关键字声明它来引用该标识符所引用的实体,但来自其他翻译单元extern
。现在,假设我们不想在其他翻译单元中使用该实体。然后,实体将exist
直到程序完成,但是当我们不声明它时,我们将无法引用它。另请注意,现在我混合了链接和生命周期这两个术语。但这是因为只有global
实体具有外部联系。不能从程序的其他部分引用函数内部的标识符。
结论:总是尽量保持简单。我很惊讶不同的人如何以不同的方式谈论这些术语。单独编译的整个过程是混乱的,因为有多个术语几乎具有相同的含义,可能每个人都会卡在这一点上。