命名的实体,比如变量、函数,复合类型在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;
所有标准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)。
