33:避免遮掩继承而来的名称

news2024/11/27 1:21:53

我们都知道在下面的代码中:

int x;//global变量
void someFunc()
{
	double x;//local变量
	cin >> x;//读一个新值赋予local变量x
}

上述读取数据的语句指涉的是local变量x,而不是global变量x,因为内层作用域的名称会遮掩外围作用域的名称。

当编译器处于someFunc的作用域内并遭遇名称x时,它在local作用域内查找是否有什么东西带着这个名称。若找到就不再找其他作用域。

本例的someFunc的x是double类型而global x是int类型,但那不要紧。

C++的名称遮掩规则(name-hiding rules)所做的唯一事情就是:遮掩名称。

至于名称是否应该为相同或不同的类型,并不重要。

结果是,本例中一个名为x的double遮掩了一个名为x的int。

现在导入继承,当位于一个derived class成员函数内指涉base class内的某物(也许是个成员函数、typedef、或成员变量)时,编译器可以找出我们所指涉的东西,因为derived class继承了声明于base class内的所有东西,实际运作方式是,derived class作用域被嵌套在base class作用域内,像这样:

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf2();
	void mf3();
	//...
};
class Derived : public Base {
public:
	virtual void mf1();
	void mf4();
	//...
};

假设derived class内的mf4的实现码部分像这样:

void Derived::mf4()
{
	//...
	mf2();
	//...
}

 当编译器看到这里使用名称mf2,必须估算它指涉什么东西。

编译器的做法是查找各作用域,看看有没有某个名为mf2的声明式。

首先查找local作用域(也就是mf4所覆盖的作用域),在那没找到任何东西名为mf2。于是查找其外围作用域,也就是class Derived覆盖的作用域。还是没找到任何东西名为mf2,于是再往外围移动,本例为base class。在那编译器找到一个名为mf2的东西,于是停止查找。若Base内还是没有mf2,查找动作便继续下去,首先找内含Base的那个namespace的作用域(若有的话),最后往global作用域找去。

现在再考虑前一个例子,这次重载mf1和mf3,并且添加一个新版mf3到Derived去。

这里发生的事情是:

Derived重载了mf3,那是一个继承而来的non-virtual函数。这会使整个设计立刻显得疑云重重。

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
	//...
};
class Derived : public Base {
public:
	virtual void mf1();
	void mf3();
	void mf4();
	//...
};

以作用域为基础的“名称遮掩规则”并没有改变,因此base class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了。从名称查找观点来看,Base::mf1和Base::mf3不再被Derived继承。

Derived d;
int x;
//...
d.mf1();//没问题,调用Derived::mf1
d.mf1(x);//错误,因为Derived::mf1遮掩了Base::mf1
d.mf2();//没问题,调用Base::mf2
d.mf3();//没问题,调用Derived::mf3
d.mf3(x);//错误,因为Derived::mf3遮掩了Base::mf3

上述规则依然适用,即使base class和derived class内的函数有不同的参数类型也适用,而且无论函数是virtual或non-virtual一体适用。

这些行为背后的基本理由是为了防止你在程序库或应用框架(qpplication framwork)内建立新的derived class时附带地从疏远的base class继承重载函数。

若想使用通过继承被遮掩的函数,可以适用using声明式:

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
	//...
};
class Derived : public Base {
public:
	using Base::mf1;
	//让Base class内名为mf1和mf3的所有东西,
	//在Derived作用域内都可见(并且public)
	using Base::mf3;
	virtual void mf1();
	void mf3();
	void mf4();
	//...
};

现在,继承机制将一如往昔地运作:

Derived d;
int x;
//...
d.mf1();//没问题,调用Derived::mf1
d.mf1(x);//现在没问题,调用Base::mf1
d.mf2();//没问题,调用Base::mf2
d.mf3();//没问题,调用Derived::mf3
d.mf3(x);//现在没问题,调用Base::mf3

这意味着若你继承base class并加上重载函数,而你又希望重新定义或覆写(推翻)其中一部分,那么你必须为哪些原本会被遮掩的每个名称引入一个using声明式,否则某些你希望继承的名称会被遮掩。

假设Derived以private形式继承Base,而Derived唯一想继承的mf1是那个无参数版本。using声明式在这里派不上用场,因为using声明式会令继承而来的某给定名称的所有同名函数在derived class中都可见。

这时我们需要的是不同的技术,即一个简单的转交函数(forwarding function):

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	//...//与前同
};
class Derived : private Base {
public:
	//转交函数,暗自成为inline
	virtual void mf1()
	{
		Base::mf1();
	}
	//...
};
Derived d;
int x;
//...
d.mf1();//没问题,调用Derived::mf1
d.mf1(x);//错误,Base::mf1被遮掩了

inline转交函数的另一个用途是为那些不支持using声明式(但,这并非正确行为)的老旧编译器另辟一条新路,将继承而得的名称汇入derived class作用域内。

总结

1.derived class内的名称会遮掩base class内的名称。在public继承下从来没有人希望如此。

2.为了让被遮掩的名称再见天日,可使用using声明式或转交函数。 

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

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

相关文章

提示词工程让儿童编程轻而易举

编写长长的代码时常令人头疼。尤其是小朋友,打字不快,但想象力丰富。 现在借助chatgpt。 一切变得超级简单。 1. https://github.com/roocell/gptCozmo 2. https://github.com/Bhood23/CozmoGPT while True:from pyChatGPT import ChatGPTimport speec…

1427205-93-3,Fmoc-Ser(Ac4Manα1-2Ac3Manα1-2Ac3Manα)-OH:一种糖基化蛋白

Fmoc-Ser(Ac4Manα1-2Ac3Manα1-2Ac3Manα)-OH,其CAS号为1427205-93-3,英文名为Fmoc-Ser(Ac4Manα1-2Ac3Manα1-2Ac3Manα)-OH。分子式为C56H67NO30,分子量为1234.13,纯度标准为95%。外形颜色为固体或粉末,包装规格有1…

重命名文件名 | 一键导出表格,让您的文件快速整理归档

您是否因为大量文件命名混乱、找文件困难而感到苦恼?现在有一个好消息,文件批量改名高手帮你解决!我们提供最简单、最快捷的方式来统一您的文件命名,无论是照片、文档或是音视频文件,只需一键即可完成重命名。而且我们…

华为OD机试真题 Java 实现【观看文艺汇演问题】【2023 B卷 100分】,附详细解题思路

一、题目描述 为庆祝中国共产党成立100周年,某公园将举行多场文艺汇演,很多演出都是同时进行。 一个人只能同时观看一场演出,且不能迟到早退。由于演出分散在不同的演出场地,所以连续观看的演出最少要有15分钟的时间间隔。 小明…

二、Drools WorkBench

一、WorkBench 简介 WorkBench 是 KIE 组件中的元素,也称为 KIE-WB,是 Drools-WB 与 JBPM-WB 的结合体。它是一个可视化的规则编辑器。WorkBench 其实就是一个 war 包,安装到 Tomcat 中就可以运行。使用 WorkBench 可以在浏览器中 创建数据对…

基于jsp+mysql+Spring+mybatis+Springboot的Springboot实现的就业信息管理平台

运行环境: 最好是java jdk 1.8,我在这个平台上运行的。其他版本理论上也可以。 IDE环境: Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以,如果编译器的版本太低,需要升级下编译器,不要弄太低的版本 tomcat服务器环…

教你如何使用自定义测试(Minium)进行微信小程序自动化测试

目录 前言: 一、 编写用例 基本操作 处理小程序API 处理小程序原生控件 数据驱动 二、 执行用例 本地执行 云测服务测试 三、 最佳实践 四、总结 前言: 微信小程序自动化测试是保障小程序质量的重要手段,Minium是一个可为微信小程…

kafka 对 java NIO 的封装

说明 本文基于 kafka 2.7 编写。author JellyfishMIX - github / blog.jellyfishmix.comLICENSE GPL-2.0 java NIO 组件 几个 java NIO 的组件。 Buffer: 缓冲区。这是一个接口,kafka 用它的 ByteBuffer 实现类,配合 SocketChannel 实现读写操作。读…

区块链产业快速发展 和数集团开启区块链应用新时代

UTONMOS区块链游戏要来了。 就在5月底,UTONMOS品牌所属公司上海和数集团在泰国发布了【神念无界】系列的多款国际版链游,包括【神念无界-源起山海】、【北荒传奇】、【神宠岛】、【神农园】等区块链游戏。 以【神念无界-源起山海】为例,其是…

Web、容器化 Native、小程序跨平台!三种跨平台方案对比

前端码农工作几年,从一家公司跳到另一家公司,永远逃不掉的是跨平台需求。除了本身应用在多平台上架的需求之外,资源有限恐怕是最大的原因,跨平台方案确实可以减少重复开发工作,降低成本和节省时间;而且掌握…

从开源到云原生,时序数据库 TDengine 六年回顾精彩纷呈

2023 年 6 月 6 日,涛思数据旗下时序数据库(Time Series Database) TDengine 迎来六周年庆典,并于北京保利国际广场T2举办了主题为“TDengine 6th Anniversary:Back to The Future”的庆典活动,设置了「TDe…

《Contrastive Learning for Unpaired Image-to-Image Translation》

Contrastive Learning for Unpaired Image-to-Image Translation 1. 摘要2. 介绍3. 相关工作3.1 图像转换、循环一致性3.2 关系保持3.3 深度网络嵌入中的感知相似性3.4 对比表示学习 4. 方法 原文及代码链接 https://github.com/taesungp/contrastive-unpaired-translation 1.…

API之Apifox和Postman工具该如何抉择?

目录 前言 一.功能列表对比 (一)接口设计与文档管理功能 (二)接口调试功能对比 (三)接口mock功能 (四)接口测试功能 二.团队协作功能 三.Apifox 没有的功能 四.产品价格 前…

代码随想录算法训练营第五十二天|300.最长递增子序列|674. 最长连续递增序列|718. 最长重复子数组

LeetCode300.最长递增子序列 动态规划五部曲: 1,dp[i]的定义:本题中,正确定义dp数组的含义十分重要。dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度。为什么一定表示 “以nums[i]结尾的最长递增子序” &#xff0c…

FP独立站卖家怎么解决收款问题?挑选支付公司有何关注点?

2023年是充满希望又充满挑战的一年。这一年,新冠肺炎疫情恢复,经济慢慢复苏,对做跨境电商的卖家来说是个不错的机遇;但由于chatgpt人工智能的出现,F牌网站被检测出来的几率大大提高……让F牌独立站卖家最头疼的是&…

使用iTerm2打造ssh神器

在日常工作中,经常要通过ssh连接远程服务器,每次连接都输入密码,会比较麻烦。 在Window系统上,我习惯使用xshell管理连接,非常方便。 在MacOS系统上,没有xshell,而一些类似xshell的工具中&#…

vue+elementui+nodejs美容院理发店产品网上商城管理系统0ffvo

在当前的信息化管理浪潮下,我国的各行业不断转向信息化,现代化的高效管理模式。研发新一代美发管理系统,使一直沿袭传统的美发管理模式而产生的管理效率较低,经营管理水平相对滞后等现象得以改善;而这种新型的美容美发…

红外人体感应灯单片机开发方案

近来,红外人体感应灯受到了居家人们关注和喜爱。为此,宇凡微推出了一款低成本红外人体感应灯单片机方案。红外人体感应灯可应用于走廊、床边、楼梯、衣柜等地方,提供柔和照明作用。人来即亮,人走即灭,不受强光影响睡眠…

[游戏开发][Unity]Assetbundle下载篇(7)获取运行时(边玩边下)下载列表

啥是运行时下载清单?现在大多数手游都会有一个边玩边下功能,会提示用户是否开启下载,要XXX流量,如果你下载完了,可能还会有奖励。 疑问:为何要有边玩边下功能? 解答:为了发包的包体…

常见的五种HDMI接口类型,你知道多少?

高清多媒体接口(High Definition Multimedia Interface)简称HDMI,是一种全数字化视频和声音发送接口,可以 同时发送未压缩的视频及音频信号 ,且发送时采用同一条线材,大大简化了系统线路的安装难度&#xf…