[cpp primer随笔] 17. 类中名字的查找机制

我发现写文章的逻辑真的很重要。如果只是简单的陈述知识点,那么阅读的体验会很糟糕。要想做到文章逻辑清晰,文笔是其次,作为作者首先就要对这个问题有比较顺畅的思路,绕后再把内容呈现出来。话不多说,开始本篇的内容。

本篇主要介绍了C++中类中名字的查找机制。

名字查找(name lookup)指的是解析一个程序中出现的名字,并且寻找到与之相匹配的声明,这是在程序的编译阶段完成的。

对于一个类外的普通名字,例如一个类型名或一个变量名,其名字查找过程比较直接。编译器会先在当前作用域内、该名字使用之前的部分查找有无该名字的声明,若无,则会去外层作用域寻找依次类推。如果最终没有找到该名字的有效声明,则判定为这是一个未定义的名字。

然而,类中名字的查找方式与方才所描述的有所不同。因为一个类定义的代码是分为两部分来编译的编译器会先编译类成员声明,再编译类内成员函数的代码块(无论成员函数的定义在类内还是类外)。

1. 类声明中的名字查找

类声明中需要进行查找的名字,包括成员函数声明中的返回类型与形参类型名,以及成员变量中的类型名。这种名字大体可以分为两种,一种是自定义类型名,另一种是类型别名。

在名字查找时,会先使用该名字的当前声明语句,在类定义内,之前是否出现过该名字的声明。若无,会在外层作用域该类定义之前的部分查找,依次类推向外拓展,直至找到匹配的声明,该名字解析成功。否则,这是一个未声明的名字。

下面是一个例子:

class NAME;   // 外层作用域1

class People{ // 作用域People,类内作用域
private:
	using MONEY = double;
	MARRIED isMarried = false; // 4. 错误,未声明的名字MARRIED
public:
	People(NAME name);   // 1. 正确
	People(AGE age);     // 2. 错误,未声明的名字AGE
	People(MONEY money); // 3. 正确
	typedef bool MARRIED;
};
// 外层作用域1,但是在类定义(使用该名字的位置)之后
using AGE = int;

上面的例子中描述了4种情况。

  • 情况1:首先我们定义了一个类People。在第一个构造函数的形参列表中,我们使用了自定义类型NAMENAME的声明虽然不在类内,但是位于People类定义所处作用域外层作用域1的前面,因此类内的名字NAME解析成功。
  • 情况2:首先类内没有,AGE是在People类定义之后定义的一个类型别名,因此解析失败。
  • 情况3:MONEY是在第三个构造函数声明之前,定义的一个类型别名,因此查找成功。
  • 情况4:isMarried是一个类型为MARRIED的成员变量。因为MARRIED本身是一个定义在该成员变量之后的一个类型别名,因此类内查找失败,外层作用域又没有MARRIED的声明,因此该名字解析失败。

此外,需要注意类中类型成员的特殊性:尽管内层作用域中对名字重新声明可以覆盖外层作用域,但是类外定义的类型别名,在成员声明中一经使用,之后的声明禁止重新定义该别名。哪怕重新声明前后,该别名表示的类型相同。(编译器不会检查这种错误,但是前后两次MONEY的类型取决于哪个,C++标准并未指定,这属于编译器具体实现问题)下面是一个例子:

using MONEY = double;
class People{ // 作用域People,类内作用域
private:
public:
	People(MONEY money);
	using MONEY = double; // 不推荐这么做
};

尽量将类型成员的声明放在类定义的一开始,有利于代码语义清晰。

2. 成员函数代码块中的名字查找

成员函数代码体的编译是在成员声明编译之后,因此无论成员函数的定义在类内与类外,均可以使用类成员声明中的所有名字

成员函数定义在类内的,其名字查找机制与成员声明相同。

成员函数定义在类外的,若函数体中出现类定义中没有声明过的名字,则会在成员函数定义所在作用域进行名字查找。与类中成员声明一样,仅在成员函数定义前声明的名字可以被成功搜寻,之后的依旧无效。当前作用域若查找失败,则会向外层作用域依次扩大搜寻范围,直至找到或者判定为名字未定义。(最大找到全局作用域)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

012.tr

1、用tr进行转换 tr是Unix命令行专家工具箱中的一件万能工具。它可用于编写优雅的单行命令。tr可以对来自标准输入的内容进行字符替换、字符删除以及重复字符压缩。tr是translate(转换)的简写,因为它可以将一组字符转换成另一组字符。 tr只…

ADI 阻抗测量开发板AD5940调试

硬件环境: 评估板A,阻抗测试板 EVAL-AD5940BIOZ,阻抗测试板信息链接如下: https://wiki.analog.com/resources/eval/user-guides/eval-ad5940/hardware/eval-ad5940bioz 评估板B,MCU控制板 EVAL-ADICUP3029,控制板信息链接如下…

【python】——控制语句和组合数据类型(其二)

🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL&#xff1a…

鸿蒙OS应用开发初体验

什么是HarmonyOS? HarmonyOS(鸿蒙操作系统)是华为公司开发的一款基于微内核的分布式操作系统。它是一个面向物联网(IoT)时代的全场景操作系统,旨在为各种类型的设备提供统一的操作系统平台和开发框架。Har…

docker删除镜像命令

在Docker中删除镜像的命令是 docker rmi。这个命令用于删除一个或多个Docker镜像。使用这个命令时,你需要指定要删除的镜像的ID或名称。以下是一些常用的用法: 删除单个镜像: docker rmi [IMAGE_ID或REPOSITORY:TAG]例如,如果你知…

最大似然估计的介绍

最大似然估计(Maximum Likelihood Estimation,简称MLE)是一种用于估计概率分布中参数的方法。该方法的核心思想是选择使得观察到的数据在给定模型下出现的概率最大的参数值作为估计值。 最大似然估计具有很好的性质,包括渐进正态性…

LTE信令流程及业务流程

1、Attach过程 完成完成鉴权、身份验证、用户注册以外,包含默认承载的建立 1)在LTE网络中,PDN连接是默认承载的建立,它是在EPS承载中建立的,主要用于在UE和PDN之间传输数据。 2)在建立PDN连接时,会通过EPS隧道连接到PD…

Windows10安装麒麟桌面V10双系统

概述 想要在Windows10操作系统中安装麒麟V10的桌面操作系统(Kylin-Desktop-V10-Professional-Release-Build1-210203-X86_64) 安装前准备 1、先搞清楚自己的电脑类型 A MBR传统bios单硬盘 B MBR 传统bios双硬盘(SSD固态硬盘机械硬盘&…

atsec at the PCI Community Meeting 2023

atsec participated in the PCI (Payment Card Industry) Security Standards Council 2023 Asia-Pacific Community Meeting held in Kuala Lumpur, Malaysia, on 15 and 16 November and hosted a booth. atsec’s principal consultant Di Li provided a presentation on “…

OceanMind海睿思数据中台迎来重磅更新,使用体验全面提升!

为了帮助客户拥有更好的产品使用体验,帮助实施数据治理项目降本增效,OceanMind海睿思的迭代更新从未止步。 OceanMind数据中台再度迎来重磅更新,该版本在大数据方面进行了规划设计,吸纳了30来自于项目的实际需求,更贴…

openldap-sasl身份认证镜像

背景 在这篇文章中,AD域信息同步至openLDAP我们使用了SASL将身份验证从OpenLDAP委托给AD”这种方案,本文主要来构建此方案的docker镜像。 sasl官网:Cyrus SASL bitnami/openldap镜像地址:containers/Dockerfile bitnami/openl…

React升级到18版本

前言 升级前react版本是16.9.0,react-dom版本为16.9.0,react-router-dom为5.1.2版本。 安装 // npm npm install react react-dom// yarn yarn add react react-dom// pnpm pnpm install react react-dom启动项目 此时,项目可以正常运行&…

计算机领域十大天神

✍️作者简介:沫小北/码农小北(专注于Android、Web、TCP/IP等技术方向) 🐳博客主页:沫小北/码农小北 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN 🔔如果文章对您有一定的帮助请&…

CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)的内部网络结构有什么区别?

【导师不教?我来教!】同济计算机博士半小时就教会了我五大深度神经网络,CNN/RNN/GAN/transformer/LSTM一次学会,简直不要太强!_哔哩哔哩_bilibili了解的五大神经网络,整理笔记如下: 视频是唐宇…

git的简单使用

git 的简单使用 前言: 为了方便理解,文中一些内容表达的不是十分准确,如有错误,欢迎大家友善的指出。 接下来就开始了!! 使用git其实就是围绕下面这个图展开的,大家可以先看下图&#xff0c…

到站上海!见证这座零碳园区的绿色低碳新选择

不知不觉中,科士达新能源的零碳足迹已遍布五洲四海,为全球各地,千行百业、千家万户,带去了源源不断的绿色能源和低碳新选择。再次启航,这一站,抵达上海世博园。 小机身,大配置,灵活适…

【开源】基于Vue.js的社区买菜系统的设计和实现

项目编号: S 011 ,文末获取源码。 \color{red}{项目编号:S011,文末获取源码。} 项目编号:S011,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 数据中心模块2.1…

Pandas 将DataFrame中单元格内的字典dict拆分成单独的列

核心是应用 pd.Series, 具体操作如下: import pandas as pddata {years: [2025],week: [{f"week_{i}": i for i in range(3)}]} df pd.DataFrame(data) print(df)df pd.concat([df, df[week].apply(pd.Series)], axis1).drop(week, axis1)…

java学习part03基本类型

22-变量与运算符-标识符的使用_哔哩哔哩_bilibili 1.标识符(变量)命名规则 2.变量类型 3.整型 4.浮点型 5.char字符 6.布尔boolean 7.基本类型的自动提升 8.强制转换 9.String String只能连接 会把其他类型的表面量转成字符串比如"true" &…

C++--第一个代码hello world

本篇开启C之旅... 先上代码&#xff1a; #include<iostream> using namespace std; int main() {cout << "hello world\n";return 0; }一. #include <iostream> 类比C语言中的#include<stdio.h>, #include <iostream>也是预处理指令…
最新文章