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

标识符是一个由程序员定义的名称,为标识区别变量、函数和数据类型等,代表程序的某些元素,变量名就是标识符的一个展现。
作用域讨论的是标识符的有效范围可见性讨论的是标识符是否可以被引用。在一个函数中声明的变量就只能在这个函数中起作用,这就是受变量的作用域和可见性的限制。作用域与可见性既相互联系又存在很大差异。

1.作用域

作用域是一个标识符在程序正文中有效的区域。C++中标识符的作用域有函数原型作用域、局部作用域(块作用域)、类作用域和命名空间作用域。

(1)函数原型作用域

函数原型作用域是C++程序中最小的作用域。在函数原型中一定要包含形参的类型说明。在函数原型声明时形式参数的作用范围就是函数原型作用域。
例如,有以下函数声明:

double area(double radius);

标识符radius的作用(或称有效)范围就在函数area形参列表的左右括号之间,在程序的其他地方不能引用这个标识符。因此标识符radius的作用域称为函数原型作用域。
【注意】由于在函数原型的形参列表中起作用的只是形参类型,标识符并不起作用,因此是允许省去的。但考虑到程序可读性,通常还是要在函数原型声明时给出形参标识符。

(2)局部作用域

【例】
在这里插入图片描述
这里函数fun的形参列表中声明了形参a,在函数体内声明了变量b,并且用a的值初始化b。接下来,在if语句中又声明了变量c。a,b,c都具有局部作用域,只是它们分别属于不同的局部作用域。
函数形参列表中形参的作用域,从形参列表中的声明处开始,到整个函数体结束是之处为止。因此,形参a的作用域从a的声明处开始,直到fun函数的结束处为止。
函数体内声明的变量,其作用域从声明处开始,一直到声明所在的块结束为止。 所谓块,就是一对大括号括起来的一段程序。在这个例子中,函数体是一个块,if语句后的分支体又是一个较小的块,二者是包含关系。因此,变量b的作用域从声明处开始,到它所在的块(即整个函数体)结束处为止,而变量c的作用域从声明处开始,到它所在的块,即分支体结束为止。
具有局部作用域的变量也称为局部变量。

(3)类作用域

类可以被看成是一组有名成员的集合,类X的成员m具有类作用域,对m的访问方式有如下三种:
①如果X的成员函数中没有声明同名的局部作用域标识符,那么在该函数内可以直接访问成员m。也就是说类的数据成员m在这样的函数中都起作用。
X的成员函数中没有声明与类中数据成员同名的局部作用域标识符的情况:

class X
{
public:X(int m = 0):m(m){}int getM(){//int m=7;return m;}
private:int m;
};
int main()
{X b(5);b.getM();cout << b.getM() << endl;
}

运行结果:
在这里插入图片描述
X的成员函数中声明了与类中数据成员同名的局部作用域标识符的情况:

class X
{
public:X(int m = 0):m(m){}int getM(){int m=7;return m;}
private:int m;
};
int main()
{X b(5);b.getM();cout << b.getM() << endl;
}

运行结果:
在这里插入图片描述
②通过表达式x.m或者X::m。这正是程序中访问对象的最基本方法。X::m的方式用于访问类的静态成员。
③通过ptr->m这样的表达式,其中ptr为指向X类的一个对象指针。
C++中,类及其对象还有其他特殊的访问和作用域规则。

(4)命名空间作用域

命名空间的概念:
在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对命名空间的。
命名空间的定义:
定义命名空间,需要使用到namespace 关键字,这个关键字的作用就是定义一个命名空间。
命名空间的语法形式如下:

namespace 命名空间名 
{命名空间内的各种声明(函数声明、类声明...)
}

一个命名空间确定了一个命名空间的作用域,凡是在该命名空间之内声明的、不属于前面所述各个作用域的标识符,都属于该命名空间的作用域。在命名空间你内部可以直接引用当前命名空间中声明的标识符,如果需要引用其他命名空间的标识符,需要使用下面的语法:

命名空间名::标识符名

例如:
定义一个命名空间

namespace SomeNs
{class SomeClass{...};void somemeFunc(){...}
}

如果需要引用类名SomeClass或者函数名somemeFunc,需要使用下面的方式:

SomeNs::SomeClass obj1;//声明一个SomeNs::SomeClass型的对象obj1

有时,在标识符前总使用这样的命名空间限定会显得过于冗长,为了解决这一问题,C++又提供了using语句,using语句有两种形式:

using 命名空间::标识符名;//1
using namespace 命名空间名;//2

第一种形式将指定的命名空间中的标识符暴露在当前的作用域中,使得在当前作用域中可以之间引用该标识符;第二种形式将指定命名空间内的所有标识符暴露在当前的作用域中,使得在当前作用域中可以直接引用该命名空间内的任何标识符。
事实上,C++标准程序库的所有标识符都被声明在std命名空间内,平时所用到的cincoutendl等标识符都是如此,因此,前面的程序中都使用了using namespace std;。如果去掉这条语句,则引用相应的标识符需要使用std::cinstd::coutstd::endl这样的语法。
命名空间也允许嵌套,例如:

namespace OuterNs
{namespace InnerNs{class SomeClass{...};}
}

引用其中的SomeClass类,需要使用OuterNs::InnerNs::SomeClass的语法形式。
此外,还有两类特殊的命名空间——全局命名空间和匿名命名空间。全局命名空间就是默认的命名空间,在显式声明的命名空间之外的标识符都在一个全局命名空间中。匿名命名空间是一个需要显式声明的没有名字的命名空间,声明方式如下:

namespace 
{匿名命名空间内的各种声明(函数声明、类声明、......)
}

在包含多个源文件的工程中,匿名命名空间常常被用来屏蔽不希望暴露给其他源文件的标识符,这是因为每个源文件的命名空间是彼此不同的,在一个源文件中没有办法访问其他源文件的匿名命名空间。
【例】作用域实例,以下声明的全局变量就具有命名空间作用域,它在整个文件中都有效。

int i;//在全局命名空间中的全局变量
namespace Ns
{int j;//在Ns命名空间中的全局变量
}
int main()
{i = 5;//为全局变量i赋值Ns::j = 6;//为Ns命名空间中的全局变量j赋值{   //子块1using namespace Ns;//使得在当前块中可以直接引用Ns命名空间中的标识符int a;    //局部变量,局部作用域a = 7;    cout << "a=" << a<< endl;//输出7int i = 8; //局部变量,局部作用域cout << "j=" << j << endl;//输出6cout << "i=" << i << endl;//输出8}cout << "i=" << i << endl;//输出5return 0;
}

运行结果:
在这里插入图片描述
在上面的例子中,变量i具有命名空间作用域,它属于全局命名空间,其有效作用范围到文件尾才结束。在主函数开始处给这个具有命名空间作用域的变量赋初值5,接下来在子块1中又声明了同名变量并赋初值8。所以第一次输出i的值为8,这是因为具有局部作用域的变量i把具有命名空间作用域的变量i隐藏了,具有命名空间作用域的变量i变得不可见。在程序运行到子块1结束后,变量i进行第二次输出时,输出的就是具有命名空间作用域的变量i的值5。变量j也具有命名空间作用域,它被声明在命名空间Ns当中,在主函数中通过Ns::j的方式引用并为其赋初值,接下来在块1中,通过using namespace Ns使得命名空间的标识符可以在该块中被直接引用,因此输出j的值时可以直接使用标识符j。
具有命名空间作用域的变量也称为全局变量。

2.可见性

从标识符引用的角度,来看标识符的有效范围,即标识符的可见性。程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。

不同作用域之间的关系:

命名空间作用域最大,接下来依次是类作用域和局部作用域。如下图所示:
在这里插入图片描述
可见性表示从内层作用域向外层作用域“看”时能看到什么,可见性和作用域之间有着密切的关系。

作用域的可见性的一般规则如下:

(1)标识符要声明在前,引用在后。
(2)在同一作用域中,不能声明同名的标识符。
(3)在没有互相包含关系的不同的作用域中声明的同名标识符互不影响。
(4)如果两个或多个具有包含关系的作用域中声明了同名标识符,则外层的标识符在内层不可见。
【例】

int i;//在全局命名空间中的全局变量
namespace Ns
{int j;//在Ns命名空间中的全局变量
}
int main()
{i = 5;//为全局变量i赋值Ns::j = 6;//为Ns命名空间中的全局变量j赋值{   //子块1using namespace Ns;//使得在当前块中可以直接引用Ns命名空间中的标识符int i = 8; //局部变量,局部作用域cout << "i=" << i << endl;//输出8}cout << "i=" << i << endl;//输出5return 0;
}

运行结果:
在这里插入图片描述

上例是命名空间作用域与局部作用域互相包含的实例,在主函数内块1之外,可以引用具有该命名空间作用域的变量,也就是说它是可见的。当程序进入块1后,就只能引用具有局部作用域的同名变量,具有命名空间作用域的同名变量被隐藏了。这也是为什么两次输出的变量i的值不同。
【注意】作用域和可见性的原则不只适用于变量名,也适用于其他各种标识符,包括常量名、用户定义的类型名、函数名、枚举类型的取值等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/17290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全进阶学习第八课——信息收集

文章目录 一、什么是信息收集&#xff1f;二、信息收集的原则三、信息收集的分类1.主动信息收集2.被动信息收集 四、资产探测1、Whois查询#常用网站&#xff1a; 2、备案信息查询#常用网站&#xff1a; 3、DNS查询#常用网站&#xff1a; 4、子域名收集#常用网站&#xff1a;#常…

C语言实用调试详解

目录 什么是bug? 调试是什么?有多重要? 调试是什么? 调试的基本步骤 Debug和Release的介绍 Windows环境调试介绍 调试环境的准备 学会快捷键 调试的时候查看程序当前信息 查看临时变量的值 查看内存信息 查看调用堆栈 查看汇编信息 查看寄存器信息 一些调试…

控制反转ioc理解,配置说明

先写个例子吧 配置文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"h…

CSS 高频按钮样式

CSS 高频按钮样式 矩形与圆角按钮 正常而言&#xff0c;我们遇到的按钮就这两种 -- 矩形和圆角&#xff1a; 它们非常的简单&#xff0c;宽高和圆角和背景色。 <div classbtn rect>rect</div><div classbtn circle>circle</div>.btn {margin: 8px aut…

【Linux命令200例】rm用来删除文件或目录(谨慎使用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜…

MongDB文档--架构体系

阿丹&#xff1a; 在开始学习先了解以及目标知识的架构体系。就能事半功倍。 架构体系 MongoDB的架构体系由以下几部分组成&#xff1a; 存储结构&#xff1a;MongoDB采用文档型存储结构&#xff0c;一个数据库包含多个集合&#xff0c;一个集合包含多个文档。存储形式&#…

前端Vue入门-day06-路由进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 路由的封装抽离 声明式导航 导航链接 两个类名 自定义高亮类名 跳转传参 1. 查询参数传参 2. 动态…

Socket 前端项目结构搭建

npm install socket.io-client --savenpm install element-plus --savenpm install vue-router4.0.12 --save简单的页面搭建 聊天系统登录前端实现 登录模板 <template><div class"login-container"><el-form ref"form" :model"fo…

Maven 打包项目后,接口识别中文乱码

背景 项目在Idea里面运行&#xff0c;调用接口发送中文消息正常&#xff0c;用Maven打包项目后&#xff0c;运行jar包&#xff0c;调用接口发送中文出现乱码。 解决方法 1.Idea编译配置 2.如果更改了上述配置之后还是没有效果&#xff0c;则在运行jar包的前面加上 -Dfile.en…

100天精通Python(可视化篇)——第96天:Pyecharts绘制多种炫酷箱形图参数说明+代码实战

文章目录 专栏导读1. 箱形图介绍1&#xff09;箱形图介绍2&#xff09;怎么看箱型图&#xff1f;3&#xff09;解释说明 2. 普通箱型图3. 水平箱型图4. 群组箱型图5. 带异常点的箱型图书籍推荐 专栏导读 &#x1f525;&#x1f525;本文已收录于《100天精通Python从入门到就业…

适配器模式与装饰器模式对比分析:优雅解决软件设计中的复杂性

适配器模式与装饰器模式对比分析&#xff1a;优雅解决软件设计中的复杂性 在软件设计中&#xff0c;我们常常面临着需要将不同接口或类协调工作的情况&#xff0c;同时还要满足灵活性和可扩展性的需求。为了应对这些挑战&#xff0c;适配器模式和装饰器模式应运而生&#xff0c…

IDEA Debug小技巧 添加减少所查看变量、查看不同线程

问题 IDEA的Debug肯定都用过。它下面显示的变量&#xff0c;有什么门道&#xff1f;可以增加变量、查看线程吗&#xff1f; 答案是&#xff1a;可以。 演示代码 代码如下&#xff1a; package cn.itcast.attempt.threadAttempt.attempt2;public class Test {public static …

GFS分布式文件系统

目录 一、GlusterFS简介 二、GlusterFS特点 1.扩展性和高性能 2.高可用性 3.全局统一命名空间 4.弹性卷管理 5.基于标准协议 三、GlusterFS 术语 1.Brick&#xff08;存储块&#xff09; 2.Volume&#xff08;逻辑卷&#xff09; 3.FUSE 4.VFS 5.Glusterd&#xf…

day48-ajax+SSM分页

AjaxSSM分页 非分页版controller及html&#xff1a; 分页模糊查询controller&#xff1a; Postman测试&#xff08;无网页&#xff09;&#xff1a; 分页网页&#xff1a; 分页网页中添加模糊查询&#xff1a; 分页网页中实现添加功能&#xff1a; &#xff08;1&am…

RabbitMQ 教程 | 第4章 RabbitMQ 进阶

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

【深度学习Week3】ResNet+ResNeXt

ResNetResNeXt 一、ResNetⅠ.视频学习Ⅱ.论文阅读 二、ResNeXtⅠ.视频学习Ⅱ.论文阅读 三、猫狗大战Lenet网络Resnet网络 四、思考题 一、ResNet Ⅰ.视频学习 ResNet在2015年由微软实验室提出&#xff0c;该网络的亮点&#xff1a; 1.超深的网络结构&#xff08;突破1000层&…

b 树和 b+树的理解

项目场景&#xff1a; 图灵奖获得者&#xff08;Niklaus Wirth &#xff09;说过&#xff1a; 程序 数据结构 算法&#xff0c; 也就说我们无时无刻 都在和数据结构打交道。 只是作为 Java 开发&#xff0c;由于技术体系的成熟度较高&#xff0c;使得大部分人认为&#xff1…

留存测试数据,Apipost接口用例详解

接口用例可以在不影响源接口数据的情况下对接口添加多个用例&#xff0c;方便测试并保存测试数据。 创建用例 左侧目录选择接口后进入接口用例页面&#xff0c;点击添加用例 在弹出窗口中修改各种参数。如登录接口&#xff0c;可修改用户名为空&#xff0c;并添加断言。 执行…

css滤镜:drop-shadow

一、用法 drop-shadow( offset-x offset-y blur-radius spread-radius color ) offset-x&#xff1a;此参数设置图像的水平偏移。正值将创建右侧的偏移量&#xff0c;负值将创建左侧的偏移量。offset-y&#xff1a;此参数设置图像的垂直偏移。正值创建到底部的偏移量&#xff…

简单版本视频播放服务器V4,layui界面

简单版本视频播放服务器V4 前一个版本内容&#xff0c;可以查看 https://blog.csdn.net/wtt234/article/details/131759154 优化内容&#xff1a; 1.返回列表的优化&#xff0c;优化了原来返回空列表名称的问题 2.前端才有layui优化内容 后端&#xff1a; package mainim…