全局范围与全局命名空间

时间:2012-04-22 14:58:32

标签: c++ namespaces scope terminology

我看到了这两个短语的用法:全局范围和全局命名空间。他们之间有什么区别?

5 个答案:

答案 0 :(得分:80)

在C ++中,每个名称的范围都超出了它的范围。范围可以通过多种方式定义:它可以由 namespace functions classes {}

因此,全局或其他命名空间定义范围。全局命名空间指的是使用::,并且在此命名空间中定义的符号被称为具有全局范围。默认情况下,符号存在于全局命名空间中,除非它在块中定义,以关键字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.
};

另请注意, name 可以由命名空间,函数或类定义的内部作用域隐藏。因此,名称空间a中的名称N会在全局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
    }
}

答案 1 :(得分:4)

“范围”是比“命名空间”更通用的术语。每个命名空间,类和代码块都定义了一个范围,在该范围内可以使用在其中声明的名称;命名空间是在类和函数之外声明的名称的容器。

“全局范围”和“全局命名空间”可以或多或少地互换使用;命名空间中声明的名称范围涵盖整个命名空间。如果你特别指的是命名空间,请使用“namespace”;如果你指的是其中名称的可见性,请使用“scope”。

答案 2 :(得分:4)

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,它留在其封闭块的范围内。我们还打印全局::a,它再次打印预期值100,因为我们已经要求全局命名空间::

命名空间语义大多是逻辑上的,它是一种将symblos彼此隔离的方式,希望避免名称冲突,它不会影响对象的生命周期。

另一方面,范围表示一个对象的生命周期,全局a在本地a之前存在,因为它比main执行得早得多。但是,范围也强制符号上的命名空间,但不像namespace那样。有不同类型的范围,globalclassfunctionblockfile等......

令人困惑的部分是,范围有时会被重载以表示特定符号的可见性,这是​​从C借用的东西,其中命名空间的概念不存在,范围用于表示生命周期和可见性。但是在C ++中,规则有所改变,但术语 scope 仍以相同的方式使用,因为这两种语言共享大量概念。

答案 3 :(得分:3)

例如,当您声明全局变量int i时,我们会说i is in the global namespacehas 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).

答案 4 :(得分:2)

@Dmitriy Ryajov

这个话题有点旧,但我想就此提供帮助。我认为你不应该让事情变得比实际更复杂。标识符的Scope是计算机程序的一部分,其中标识符(引用程序中某个实体的名称)可用于查找被引用的实体。因此术语范围仅适用于标识符,我们不应将其与对象的生命周期混合。它们有些联系,但不应混淆。对象的生命周期由我们为该对象分配内存的位置表示。因此,例如,如果在堆栈上分配了内存,则在函数完成后将立即释放内存。所以它取决于我们存储对象的位置,并且表示它的生命周期。范围只说:“这是一个对象的名称,我们可以在此之前使用此名称作为对象”。因此,正如我所说的,术语scope仅用于对象的标识符,而生命周期是由我们存储对象的位置表示的其他内容。

此外,我想谈谈与此密切相关的linkage。这有时也令人困惑。假设我们在translation unit中有一些引用某些对象的标识符。 other翻译单元中的相同标识符是否将引用相同的实体由链接表示。因此,例如,如果标识符具有外部链接,我们可以通过使用关键字extern来声明该标识符引用的实体,但可以引用其他翻译单元。现在,假设我们不想在其他翻译单元中使用该实体。然后,实体将exist直到程序结束,但是当我们不声明它时,我们将无法引用它。另请注意,现在我混合了术语链接和生命周期。但这是因为只有global个实体具有外部链接。函数内的标识符不能从程序的其他部分引用。

结论:总是尽量保持简单。我很惊讶不同的人如何不同地谈论这些术语。单独编译的整个过程令人困惑,因为有多个术语具有几乎相同的含义,并且可能每个人都会陷入困境。