c++教程(十:Name visibility)

    xiaoxiao2026-04-21  6

    ————————————————————————

    该系列教程为翻译c++官方教程,点击参考英文原版,水平有限,翻译不通之处敬请谅解!

    ————————————————————————

    范围

    命名的实体,比如变量、函数,复合类型在c++中,在使用前都需要先声明,这点在编程的时候,声明位置的不同会影响它的可使用范围。

    在所有块的外面进行声明的具有全局范围,也就是说它可以在代码的任何地方被使用。然而在一个块里面声明的,比如函数里面或者一个被选择的块里面,只具有块的可使用范围,只能在块的里面被使用,在外面是不可以被使用的。

    这种在块里面使用的被称为局部变量。

    例如,一个在块里面声明的局部变量在函数外面就不能被使用:

    int foo; // global variable int some_function () { int bar; // local variable bar = 0; } int other_function () { foo = 1; // ok: foo is a global variable bar = 2; // wrong: bar is not visible from this function }

    在同一个范围内,一个名字的实体只能有一个,比如,在一个快内不能有两个变量拥有相同的名字:

    int some_function () { int x; x = 0; double x; // wrong: name already used in this scope x = 0.0; }

    一个实体的可见性与块范围扩展到块结束,包括内块。然而,一个内部块,因为它是一个不同的块,可以重新利用在外部范围内存在的一个名称来引用一个不同的实体,在这种情况下,名称将只在内部块引用一个不同的实体,隐藏它以外的实体。然而在它之外,它仍然会指向原来的实体。例如:

    // inner block scopes #include <iostream> using namespace std; int main () { int x = 10; int y = 20; { int x; // ok, inner scope. x = 50; // sets value to inner x y = 50; // sets value to (outer) y cout << "inner block:\n"; cout << "x: " << x << '\n'; cout << "y: " << y << '\n'; } cout << "outer block:\n"; cout << "x: " << x << '\n'; cout << "y: " << y << '\n'; return 0; }

    注意的是y并没有被隐藏,也就是y会指向外部块变量。

    在引入一个块的声明中声明的变量,如在循环条件下声明的函数参数和变量(例如,在for或if语句中)上声明的变量是局部的块。

    命名空间

    一个实体只有具有具体的名字以及作用空间的时候才能存在。对于局部变量来说这很少是一个问题,因为块往往是相对较短,名称在其中有特定的目的,如命名一个计数器变量,一个参数等。

    但非局部变量就带来更多的命名冲突,特别是考虑到库可能声明的许多函数,类型和变量,他们处于不同地方,其中一些非常通用。

    命名空间允许我们将实体集合起来,否则就是全局变量作用在较窄范围,给他们的命名空间范围。这允许将程序的元素组织成由名称所指的不同的逻辑范围内。

    声明一个命名空间可以如下:

    namespace identifier { named_entities }

    这里identifier是任何有效的标识符,named_entities是一系列变量、类型和函数的标识符,包含在该命名空间中。例如:

    namespace myNamespace { int a, b; }

    这种情况下,变量a,b就是该命名空间下的一般变量。 这些变量可在其命名空间的访问,他们的标识符为(a或b),但如果从mynamespace命名空间外面外面访问必须加上限定作用域操作符访问::。例如,从mynamespace外面访问一个变量他们应该是:

    myNamespace::a myNamespace::b

    命名空间对于解决名字的冲突来说非常有用。比如:

    // namespaces #include <iostream> using namespace std; namespace foo { int value() { return 5; } } namespace bar { const double pi = 3.1416; double value() { return 2*pi; } } int main () { cout << foo::value() << '\n'; cout << bar::value() << '\n'; cout << bar::pi << '\n'; return 0; }

    在这个例子中,两个函数拥有一样的名字value,一个是定义在命名空间foo中,一个是定义在bar中,因为命名空间的因素使得定义没有发生冲突错误。注意pi是如何通过命名空间bar被引用的,在main函数中是通过命名空间使用的bar::pi。

    namespace foo { int a; } namespace bar { int b; } namespace foo { int c; }

    这里声明了三个变量:a和c都是在命名空间foo中,而b是命名空间bar下。命名空间可以跨越不同的变换单元(即在源代码的不同文件)。 Using 关键字using是将一个名字应用到当前声明空间范围内(比如块),这样可以避免来描述这个名字。如:

    // using #include <iostream> using namespace std; namespace first { int x = 5; int y = 10; } namespace second { double x = 3.1416; double y = 2.7183; } int main () { using first::x; using second::y; cout << x << '\n'; cout << y << '\n'; cout << first::y << '\n'; cout << second::x << '\n'; return 0; }

    注意的是,在main函数中,变量x是如何指向first::x的,y是如何指向second::y的,只是使用了using。变量first::x与second::y也可以被使用,只是需要全名。 该关键字using也可以被用作一个指令来引入一个完整的命名空间:

    // using #include <iostream> using namespace std; namespace first { int x = 5; int y = 10; } namespace second { double x = 3.1416; double y = 2.7183; } int main () { using namespace first; cout << x << '\n'; cout << y << '\n'; cout << second::x << '\n'; cout << second::y << '\n'; return 0; }

    在这种情况下,通过声明我们使用命名空间first,所有在first命名空间中得变量都可以直接使用而不需要使用空间头引用部分,像x和y。   using和using namespace只有在同一个块中有有效性,如果他们是直接使用在全局范围内,那么他们表示在整个源代码文件。例如,它将可能首先使用一个命名空间的对象,然后在不同块中的代码通过分裂得到另一个。

    // using namespace example #include <iostream> using namespace std; namespace first { int x = 5; } namespace second { double x = 3.1416; } int main () { { using namespace first; cout << x << '\n'; } { using namespace second; cout << x << '\n'; } return 0; }

    命名空间别名

    已经存在的命名空间可以新的名字来代替,格式为:

    namespace new_name = current_name;

    std namespace

    所有标准c++存在的模块(变量、类型、常量、函数)都在std命名空间中被声明。在这些教程的许多例子中我们也可以看到,一直在包含下面这样一行代码:

    using namespace std;

    这样使得所有的标准命名空间的名称可以直接在代码中调用。在这些教程中,以方便理解和缩短例子代码量,但许多程序员喜欢在他们的程序中限定每一个使用的标准库的元素。例如:

    cout << "Hello world!";

    一般会写成:

    std::cout << "Hello world!";

    不管std的命名空间是否已经使用using声明,这种全部完整的写法不管在哪里都不会影响函数的功能。它主要是一个风格偏好的问题,对多个项目的混合库来说,明确的空间来源往往是首选。

    存储类

    被分配给程序的全局或命名空间范围的变量存储于整个持续时间。这是被称为静态存储,它与存储为局部变量(那些在一个块中声明)的对比。这些使用被称为自动存储。局部变量的存储只在声明的块中可用,在该块中,相同的存储可用于使用该局部变量某些其他函数。

    但有另一个很大的区别在静态变量存储和自动变量存储之间是: - 静态存储变量(如全局变量)不是显式初始化而是自动初始化为零。 - 自动存储变量(如局部变量),没有显式初始化也不初始化,从而有一个不确定的值。

    例如:

    // static vs automatic storage #include <iostream> using namespace std; int x; int main () { int y; cout << x << '\n'; cout << y << '\n'; return 0; }

    实际的输出可能会变化,但是x的值一定是0,而y的值就不确定了(可能包括0)。

    转载请注明原文地址: https://ju.6miu.com/read-1309068.html
    最新回复(0)