[C++]标识符的作用域与可见性

文章详细阐述了C++中标识符的作用域,包括函数原型作用域、块作用域、类作用域和全局作用域(命名空间),并解释了可见性如何影响标识符的使用。在局部块中,同名变量会屏蔽全局变量,展示了作用域和可见性如何相互作用。同时,提到了命名空间作为解决标识符冲突的机制,以及使用`iostream`与`iostream.h`的区别。
摘要由CSDN通过智能技术生成

标识符的作用域与可见性

作用域表示一个标识符(变量)的有效范围,即起作用的范围;可见性表示一个标识符是否可以被引用,即在编写程序的位置是否可以看到该标识符。两者之间既相互联系,又有很大的区别。

作用域

C++语言中的标识符作用域主要有局部作用域(包括函数原型作用域,块作用域),类作用域和全局作用域(命名空间)。标识符的作用域属性描述了在程序文件中一个标识符的有效区域。

1.函数原型作用域

函数原型作用域是C++程序中范围最小的作用域,仅存在于函数原型声明的括号中。例如:

double getArea(double radius);

上例声明了一个计算圆面积的函数原型,其形参radius是double类型,表示需要计算面积圆的半径,其作用范围起止于形参列表的左右括号之间。程序的其他地方不可以引用该标识符,其目的只是为了增加程序的可读性,可以省略不写。
上例的声明也可以这样进行:

double getArea(double);

2.块作用域

程序块一般指的是具有独立功能的小程序片段,如一个分支语句,一个循环结构的结构体或者一个函数体等,一般用{}包括起来,有时候也可以人为的使用一对花括号将一段代码包括起来构成程序块。
在程序块中声明的标识符只能在块内起作用,例如:

void fun(int x)
{
    int y = x;
    cin>>y;
    if(y>0){
        int z;
        ...
    }
    ...
}

上面是一个函数的定义,共声明了三个变量x,y,z。其中,x是函数的形参,可以在函数体中使用(形参x的作用域,注意函数定义与函数声明的区别);y是在函数体内部声明的局部变量,其作用域是从声明的位置开始,直到函数块结束为止(函数结束的右花括号为标志);变量z也是一个局部变量,是在if语句后面还有块中声明的。变量z的作用域从声明的位置开始,到if语句块结束为止,即使if语句后面还有函数体的其他语句,但是变量z已经不起作用了。

3.类作用域

从作用域的角度可以把类理解成一组数据成员和函数成员的集合。

类中的成员都具有类作用域,表示这些成员是属于该类的,因此在访问类的成员时需要通过类名限定。例如类X有一个成员名称为M,则程序中访问M的方式有以下几种情况:

(1) 如果在X的成员函数钟没有声明同名的局部作用域标识符,那么在该成员函数内可以直接访问成员M。
(2) 通过表达式x.M或者X::M访问。其中x是类X的对象,通过这种方式可以访问类的静态成员。
(3) 通过表达式ptr->M访问,其中ptr是指向类X某个对象的指针。

4.命名空间作用域

与局部作用域相对应的是文件作用域,也称为全局作用域,即在程序文件中全局位置声明的标识符在整个文件中都可以引用。

定义在所有函数之外的标识符具有文件作用域,作用域从定义处开始到整个源文件结束。文件中定义的全局变量和函数都具有文件作用域。如果某个文件中说明了具有文件作用域的标识符,该文件又被另一个文件包含,则该标识符的作用域会延伸到新的文件中。
但是,如果一个大型程序由多个程序文件(模块)构成,且这样程序文件中有同名的标识符,此时引用标识符就会产生冲突,为此我们先介绍一下命名空间的概念。

C++引入命名空间的概念是为了解决不同模块或者函数库中相同标识符冲突的问题。

有了命名空间的概念,标识符就被限制在特定的范围(函数)内,不会引起命名冲突。最典型的例子就是标准命名空间,即std命名空间,C++标准库中所有的标识符都包含在该命名空间中。

如果确信在程序中引用某个或者某些程序不会引起命名冲突(即库中的标识符不会在程序中代表其他函数名称),那么可以通过using操作符来简化对程序库中标识符的使用。

#include <iostream>
using namespace std;

int main(void)
{
	cout<<"Hi~"<<endl;
	return 0;
} 

如果不使用using namespace std;,那么可以使用如下语句进行输出:

std::cout<<"Hi~"<<std::endl;

接下来,讲一下和<iostream.h>之间的区别。
前者没有后缀,实际上在编译器include文件夹里,二者是两个文件,里面的代码是不一样的。对于后缀为.h的头文件,C++标准已经明确提出不支持了,早些时候的实现将标准库功能定义在全局空间中,声明在带.h后缀的头文件里。C++标准为了和C区别,也为了正确使用命名空间,规定头文件不使用后缀.h。因此,当使用<iostream.h>时,相当于在c中调用函数库,使用的是全局命名空间,也就是早期的C++实现;当使用时,该头文件没有定义全局命名空间,必须使用namespace std,这样才能正确使用cin,cout等输入/输出流的功能。实际上,C++标准程序库的所有标识符都被声明在标准命名空间即std命名空间内,如cin,cout,endl等标识符。

/*标识符作用域示例*/
#include <iostream>
using namespace std;
int x;	//在全局命名空间中声明的全局变量 
namespace temp{
	int y;	//在temp命名空间中声明的全局变量 
} 
int main(void)
{
	x = 5;//为全局变量x赋值
	temp::y = 6;//为全局变量y赋值
	{
		using namespace temp;//表示在当前块中可以引用temp空间的标识符
		int x;//声明局部变量x 
		x = 7;
		cout<<"x = "<<x<<endl;
		cout<<"y = "<<y<<endl;
		//return 1; 
	} 
	cout<<"x = "<<x<<endl;
} 

运行结果如下:
20230106

可见性

标识符的可见性是从引用该标识符的角度考察一个变量在当前位置能否被使用。

如果标识符在这个位置可见,则表示此时可以访问该标识符的值,该标识符一定在其作用域内。但有时候标识符尽管在其作用域内,也不可见,即不能够引用。

/*显示同名变量可见性的例子*/
#include <iostream>
using namespace std;
int n = 100;
int main(void){
	int i = 200,j = 300;
	cout<<n<<'\t'<<i<<'\t'<<j<<'\t'<<endl;//输出全局变量n和外层局部变量i,j
	{
		int i = 500,j = 600,n;
		n = i +j;
		cout<<n<<'\t'<<i<<'\t'<<j<<'\t'<<endl;//输出内层局部变量i,j,n
		cout<<::n<<endl;//输出全局变量n 
	} 
	n = i+j;
	cout<<n<<'\t'<<i<<'\t'<<j<<'\t'<<endl;//输出全局变量n和外层局部变量i,j	
	return 0;
}

运行结果如下:
20230107_1
上例在局部块中声明了与全局变量n同名的变量,因此在局部块中尽管全局变量n在其作用域内,但是访问的变量n确实局部块中声明的,即全局变量n在局部块中不可见,被同名的局部变量屏蔽了。
作用域与可见性的特征不仅适用于变量,也适用于常量,用户定义类型名,函数名以及枚举类型等.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值