一、标识符的作用域与可见性
作用域讨论的是标识符的有效范围,可见性讨论的是标识符是否可以被引用。
二、作用域
作用域是一个标识符在程序正文中有效的区域。C++中标识符的作用域有函数原型作用域、局部作用域(块作用域)、类作用域和命名空间作用域。
1.函数原型作用域
C++程序中最小的作用域。在函数原型声明时形式参数的作用范围就是函数原型作用域。
例:
double area{double radius};//标识符radius
注:标识符radius的作用域范围就是在函数area形参列表的左右括号之间,在程序的其他地方不能引用这个标识符。
在函数原型的形参列表中起作用的只是形参类型,标识符并不起作用,因此可以省略标识符,但为了程序的可读性,通常在函数原型声明时给出标识符。
2.局部作用域
①函数形参列表中的形参的作用域,从形参列表中的声明处开始,到整个函数体结束之处为止。
②函数体内声明的变量,其作用域从声明处开始,一直到声明所在的块结束的大括号为止。
具有局部作用域的变量也称局部变量。
void fun(int a){//a的作用域整个函数体 int b=a;//b的作用域大括号里 cin>>b; if (b<0){ int c;//c的作用域 if的大括号里 ... } }
再例:
#include <iostream> using namespace std; void anotherFunction() ; //函数原型 int main() { int num = 1; //主函数main中的num cout << "In main, num is " << num << endl; anotherFunction(); cout << "Back in main, num is still " << num << endl; return 0; } void anotherFunction() { int num = 20; //函数anotherFunction中的num cout << "In anotherFunction, num is " << num << endl; }
注:虽然有两个名为 num 的变量,但是程序在同一时间只能“看到”其中一个,因为它们在不同的函数中。
两个函数的封闭性质,“{}”分隔变量的作用域。第一个main变量仅在main函数中可见;第二个num仅在anotherFunction函数中可见。
3.类的作用域
类可以被看成一组有名成员的集合,类X的成员m具有类的作用域,对m的访问有如下三种方式:、
①如果X的成员函数中没有声明同名的局部作用域标识符,那么可以直接访问m。也就是说m在这样的函数中都起作用。
Clock globClock; globClock.showtime();//对象的成员函数具有类的作用域
②通过表达式x.m或X::m。这是访问对象成员的最基本方法。X::m的方式用于访问类的静态成员。
void Clock::showtime()
③使用ptr->m,其中ptr为指向X类的一个对象的指针。
Student *student = new Student(); student->show();
4.命名空间作用域
命名空间的语法形式:
namespace 命名空间名{ 命名空间内的各种声明(函数声明、类声明......) }
注:
一个命名空间确定了一个命名空间的作用域,凡是在该命名空间之内声明的、不属于前面所述各个作用域的标识符,都属于该命名空间作用域。
①如需在该命名空间内需要引用其他命名空间的标识符,语法形式如下:
命名空间名::标识符
namespace SomeNs{ class SomeClass{...}; } //如需引用类名SomeClass或函数名someFunc SomeNs::SomeClass obj1;//声明一个SomeNS型的对象obj1
②为了避免标识符前总使用上面的命名空间限定显得冗长,C++提供了using语句
两种形式
using 命名空间名::标识符名;//将指定的标识符暴露在当前作用域内,使得在当前作用域内可以直接使用该标识符 using namespace 命名空间名;//将指定命名空间内的所有标识符暴露在当前作用域内,使得在该命名空间内可以直接使用任何标识符
③命名空间允许嵌套
namespace OuterNs{ namespace InnerNs{ class SomeClass(...); } }
④特殊的命名空间:全局命名空间和匿名命名空间
全局命名空间:是默认的的命名空间,在显式声明的命名空间之外生命的标识符都在一个全局命名空间中
匿名命名空间:是一个需要显式声明的没有名字的命名空间,例如:
namespace{ 匿名命名空间内的各种声明(函数声明、类声明、......) }
二、可见性
定义:程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。
作用域可见性的一般规则如下:
①标识符要声明在前,引用在后
②在同一作用域中不能声明同名的标识符
③在没有互相包含关系的不同的作用域中声明的同名标识符,互不影响
④如果在两个或者多个具有包含关系的作用域中声明了同名标识符,则外层标识符在内层不可见
三、程序实例
#include <iostream> using namespace std; int i; //在全局命名空间中的全局变量 namespace Ns{ int j; //在Ns命名空间中的全局变量 } int main(){ i=5; //为全局变量i赋值 Ns::j=6; //为全局变量j赋值 { using namespace Ns; //使当前块中可以直接引用Ns命名空间的标识符 int i; //局部变量,局部作用域 i=7; cout<<"i="<<i<<endl; cout<<"j="<<j<<endl; } cout<<"i="<<i<<endl; return 0; }
注意:5-1中声明的全局变量就是具有命名空间的作用域,他们在整个文件中都有效。(具有命名空间作用域的变量也成为全局变量)
①变量 i 是全局命名空间,有效范围直到文件尾。
②在主函数开始处给 i 赋初值5,接下来又声明了同名变量并赋初值7。第一次输出的结果是7,因为具有局部作用域的变量 i 把具有命名空间作用域的 i 隐藏了,于是具有命名空间作用域的 i 变得不可见。
③第一个块运行结束,输出的 i 的值为7,因为具有局部作用域的 i 不在有效范围之内了,现在处在有效范围内的变量只有具有命名空间作用域的那个变量。
④j被声明在命名空间 Ns 中,在主函数中通过 Ns::j 的方式引用,为其赋值。