67

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

4

5 回答 5

96

在 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
    }
}
于 2012-04-22T15:04:04.087 回答
7

例如,当您声明一个全局变量int i时,我们说i is in the global namespaceand 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).
于 2012-04-22T15:09:56.797 回答
7

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

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

于 2012-04-22T15:11:34.193 回答
5

范围表示对象的生命周期,您可以拥有一个只要程序执行就存在的全局变量,或者您可以拥有一个具有块范围的变量,只要该代码块执行就存在。考虑这个例子:

#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,这显然是意料之中的,因为我们正在重新定义哪个叶子amain它的封闭块的范围内。我们还打印了 global ::a,它再次打印了预期值 100,因为我们已经请求了 global namespace ::

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

另一方面,范围表示对象的生命周期,全局a在局部之前出现,a因为它的构造比 main 执行要早得多。但是,作用域也会在符号上强制使用名称空间,但与 a 的方式不同namespace。有不同种类的范围,global, class, function, block,file等等...

令人困惑的部分是作用域有时被重载以表示特定符号的可见性,这是​​从 C 中借来的东西,其中不存在命名空间的概念,而作用域被用来表示寿命和可见性。然而,在 C++ 中,规则发生了一些变化,但术语作用域仍然以相同的方式使用,因为这两种语言有很多概念。

于 2012-04-22T16:47:36.460 回答
4

@Dmitriy Ryajov

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

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

结论:总是尽量保持简单。我很惊讶不同的人如何以不同的方式谈论这些术语。单独编译的整个过程是混乱的,因为有多个术语几乎具有相同的含义,可能每个人都会卡在这一点上。

于 2014-03-03T22:01:35.367 回答