当前位置: 首页 > news >正文

C++ 派生类成员的标识与访问——作用域分辨符

在派生类中,成员可以按访问属性分为以下四种:
(1)不可访问成员。这是从基类私有成员继承下来的,派生类或是建立派生类对象的模块都无法访问到它们,如果从派生类继续派生新类,也是无法访问的。
(2)私有成员。包括从基类继承过来成员以及新增的成员,在派生类内部可以访问,但是建立派生类对象的模块无法访问,继续派生,就变成了新的派生类中的不可访问成员。
(3)保护成员。可能是新增也可能是从基类继承过来的,派生类内部成员可以访问,建立派生类对象的模块无法访问,进一步派生,在新的派生类中可能成为私有成员或者保护成员。
(4)公有成员。派生类、建立派生类对象的模块都可以访问,继续派生,可能是新派生类中的私有或者保护成员。

在对派生类的访问中,我们只能访问一个能够唯一标识的可见成员。如果通过某一个表达式能引用的成员不只一个,称为有二义性。

1.作用域分辨符

作用域分辨符就是我们常见的“::”,它可以用来限定要访问的成员所在的类的名称。一般的使用形式为:

类名::成员名//数据成员
类名::成员名(参数表)//函数成员

2.作用域分辨符在类族层次结构中唯一标识成员

对于在不同的作用域声明的标识符,可见性原则是:如果存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,那么外层标识符在内层仍然可见;如果在内层声明了同名标识符,则外层标识符在内层不可见,这时称为内层标识符隐藏了外层同名标识符,这种现象叫做隐藏规则

在类的派生层次结构中,基类的成员和派生类新增的成员都具有作用域。二者的作用范围不同,是相互包含的两个层,派生类在内层。这时,如果派生类声明了一个和某个基类成员同名的新成员,派生类的新成员隐藏了外层基类中的同名成员,直接使用成员名只能访问到派生类的成员。如果派生类中声明了与基类成员函数同名的新函数,即使函数的参数表不同,从基类继承的同名函数的所有重载形式也都会被隐藏。。如果要访问隐藏的成员,就需要使用作用域分辨符和基类名来限定。

对于多继承情况,首先考虑各个基类之间有没有继承关系,同时也没有共同基类的情况。最经典的情况就是所有基类都没有上级基类。如果某派生类的多个基类拥有同名成员,同时,派生类又新增这样的同名成员,在这种情况下,派生类成员将隐藏所有基类的同名成员。 这时,使用“对象名.成员名”或者“对象指针->成员名”的方式可以唯一标识和访问派生类的新增成员,基类的同名成员也可以使用基类名和作用域分辨符访问。但是,如果派生类没有声明同名成员,使用“对象名.成员名”或者“对象指针->成员名”的方式就无法唯一标识成员。这时,从不同基类继承过来的成员具有相同的名称,同时具有相同的作用域,这时就必须通过基类名和作用域分辨符来标识成员。

【例】定义基类B1,B2,由基类B1,B2共同公有派生产生新类D。两个基类中都声明了数据成员v和函数fun,在派生类中新增同名的两个成员。这时的D类中共含有6个成员,而这6个成员只有两个名字。

#include<iostream>
using namespace std;class B1//定义基类B1
{
public:int v;void fun(){cout << "基类B1的成员" << endl;}
};class B2//定义基类B2
{
public:int v;void fun(){cout << "基类B2的成员" << endl;}
};class D :public B1, public B2//定义派生类D
{
public:int v;//同名数据成员void fun()//同名函数成员{cout << "派生类D的成员" << endl;}
};int main()
{D d;D* p = &d;d.v = 1;//对象名.成员名标识d.fun();//D类对象d访问D类成员函数fund.B1::v = 2;//作用域分辨符标识d.B1::fun();//D类对象d访问B1类成员函数funp->B2::v = 3;//作用域分辨符标识p->B2::fun();//D类对象d访问B2类成员函数funreturn 0;
}

在这里插入图片描述
在主函数中,创建了一个派生类D的对象d,根据隐藏规则,如果通过成员名称来访问该类的成员,就只能访问到派生类新增的两个成员,从基类继承过来的成员由于外层作用域被隐藏。这时,就必须使用类名和作用域分辨符来访问从基类继承来的成员。

主函数中后面两组语句:

	d.B1::v = 2;//作用域分辨符标识d.B1::fun();//D类对象d访问B1类成员函数funp->B2::v = 3;//作用域分辨符标识p->B2::fun();//D类对象d访问B2类成员函数fun

就是分别访问由基类B1、B2继承来的成员。通过作用域分辨符,明确地唯一标识了派生类中由基类所继承来的成员,达到了访问的目的,解决了成员被隐藏的问题。

如果在上例中,派生类没有声明与基类同名的成员,那么采用“对象名.成员名”就无法访问到任何成员,来自B1、B2 类的同名成员具有相同的作用域,系统根本无法进行唯一标识,这时就需要使用作用域分辨符。将上例中的派生类改为如下形式:

class D :public B1, public B2//定义派生类D
{};

程序其余部分不改变,主函数中“对象名.成员名”的访问方式就会出错:
在这里插入图片描述
如果希望 d.v = 1;d.fun();的用法不产生二义性,可以使用using关键字加以澄清。例如:

class D :public B1, public B2//定义派生类D
{
public:using B1::v;using B1::fun;
};

这样,主函数中的 d.v = 1;d.fun();都可以明确表示对B1中的相关成员的引用了。

using的一般功能是将一个作用域中的名字引入到另一个作用域中,它还有一个非常有用的用法:将using用于基类中的函数名,这样派生类中如果定义同名但参数不同的函数,基类的函数不会被隐藏,两个重载函数将会并存在派生类的作用域中。例如:

#include<iostream>
using namespace std;class B1//定义基类B1
{
public:int v;void fun(){cout << "基类B1的成员" << endl;}
};class D2 :public B1
{
public:using B1::fun;void fun(int i){cout << i << endl;}
};int main()
{D2 dd;dd.fun();dd.fun(5);return 0;
}

运行结果:

在这里插入图片描述
这时使用D2的对象,既可以直接调用基类B1中的无参数的fun,又可以直接调用派生类D2中带int型参数的fun函数。

如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来的,在这些直接基类中,从上一级基类继承来的成员就拥有相同的名称,因此派生类中也就会产生同名的现象,对这种类型的同名成员也要使用作用域分辨符来唯一标识,而且必须用直接基类来进行限定。

【例】有一个基类B0,声明了数据成员v0和函数成员fun0,由B0公有派生了类B1和类B2,在以B1,B2作为基类共同公有派生了新类D。在派生类中不再添加新的同名成员,这时的D类,就含有通过B1,B2继承来的基类B0中的同名成员v0和fun0。

class B0
{
public:int v0;void fun0(){cout << "基类B0的成员" << endl;}
};
class B1 :public B0
{
public:int v1;};
class B2 :public B0
{
public:int v2;
};
class D :public B1, public B2
{
public:int v;void fun(){cout << "基类D的成员" << endl;}
};int main()
{D d;d.B1::v0 = 2;d.B1::fun0();d.B2::v0 = 3;d.B2::fun0();return 0;
}

运行结果:
在这里插入图片描述
分析:
在主函数中,创建了派生类D的对象d,如果只通过成员名来访问该类的成员v0和fun0,系统无法唯一确定要引用的成员。这时,必须采用作用域分辨符,通过直接基类名来确定要访问的从基类继承来的成员。
这种情况下,派生类的对象在内存中就同时拥有成员v0的两份同名副本。对于数据成员来讲,虽然两个v0可以分别通过B1和B2调用B0的构造函数进行初始化,可以存放不同的数值,也可以使用作用域分辨符通过直接基类名限定来分别进行访问,但是很多情况下,我们只需要一个数据副本。同一成员的多份副本增加了内存的开销。C++中提供了虚基类技术解决这一问题。

【注意】上例中,其实B0类的函数成员fun0()的代码始终只有一个副本,之所以调用fun0函数时仍然需要用基类名B1和B2加以限定,是因为调用非静态成员函数总是针对特定的对象,执行函数时需要将指向该类的一个对象的指针作为隐含的参数传递给被调函数来初始化this指针。上例中,D类的对象中存在两个B0类的子对象,因此调用fun0函数时,需要使用B1和B2加以限定,这样才能明确针对哪个B0对象调用。

相关文章:

C++ 派生类成员的标识与访问——作用域分辨符

在派生类中&#xff0c;成员可以按访问属性分为以下四种&#xff1a; &#xff08;1&#xff09;不可访问成员。这是从基类私有成员继承下来的&#xff0c;派生类或是建立派生类对象的模块都无法访问到它们&#xff0c;如果从派生类继续派生新类&#xff0c;也是无法访问的。 &…...

SQL注入实操三(SQLilabs Less41-65)

文章目录 一、sqli-labs靶场1.轮子模式总结2.Less-41 stacked Query Intiger type blinda.注入点判断b.轮子测试c.获取数据库名称d.堆叠注入e.堆叠注入外带注入获取表名f.堆叠注入外带注入获取列名g.堆叠注入外带注入获取表内数据 3.Less-42 Stacked Query error baseda.注入点…...

(亲测解决)PyCharm 从目录下导包提示 unresolved reference(完整图解)

最近在进行一个Flask项目的过程中遇到了unresolved reference 包名的问题&#xff0c;在网上找了好久解决方案&#xff0c;并没有一个能让我一步到位解决问题的。 后来&#xff0c;我对该问题和网上的解决方案进行了分析&#xff0c;发现网上大多数都是针对项目同一目录下的py…...

【AI量化模型】跑通baseline

跑通baseline 任务学习内容特征工程模型训练与验证 bug未纠错的结果 任务 教程部署在百度 AI Studio&#xff0c;可以一键fork运行代码&#xff0c;选择*v100 32g1*的配置&#xff0c;baseline运行大约20分钟&#xff0c;再加上进阶部分大约40分钟 学习内容 特征工程 构建基…...

ElasticSearch:全文检索及倒排索引原理

1.从全文检索说起 首先介绍一下结构化与非结构化数据&#xff1a; 结构化数据将数据具有的特征事先以结构化的形式定义好&#xff0c;数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构&#xff0c;数据特征直接体现在表结构的字段上&#xff0c;…...

blk_mq_alloc_tag_set函数struct blk_mq_tag_set结构体学习

struct blk_mq_tag_set结构体 include/linux/blk-mq.h struct blk_mq_tag_set {unsigned int *mq_map;const struct blk_mq_ops *ops;unsigned int nr_hw_queues;unsigned int queue_depth; /* max hw supported */unsigned int reserved_tags;unsigned int cmd_size; /…...

Windows搭建Snort环境及使用方式

目录 0x01 前置环境0x02修改配置文件0x03 自测0x04 使用0x05 感言 0x01 前置环境 环境描述windows10snort2.9.2https://www.snort.org/downloads 先把上面环境下载好&#xff01; 需要注意的是安装npcap这个软件 0x02修改配置文件 软件安装目录&#xff1a;C:/Snort/ 配置文…...

Android network — iptables四表五链

Android network — iptables四表五链 1. iptables简介2. iptables的四表五链2.1 iptables流程图2.2 四表2.3 五链2.4 iptables的常见情况 3. NAT工作原理3.1 BNAT3.2 NAPT 4. iptables配置 本文主要介绍了iptables的基本工作原理和四表五链等基本概念以及NAT的工作原理。 1. i…...

【C++从0到王者】第十六站:stack和queue的使用

文章目录 一、stack的使用1.stack的介绍2.stack的使用 二、queue的使用1.queue的护额晒2.queue的使用 三、stack和queue相关算法题1.最小栈2.栈的压入、弹出序列3.逆波兰表达式4.两个栈实现一个队列5.用两个队列实现栈6.二叉树的层序遍历1.双队列2.用一个变量levelSize去控制 7…...

centos7 部署Tomcat和jpress应用

目录 一、静态、动态、伪静态 二、Web 1.0 和 Web 2.0 三、centos7 部署Tomcat 3.1 安装、配置jdk 3.2 安装 Tomcat 3.3 配置服务启动脚本 3.3.1 创建用户和组 3.3.2 创建tomcat.conf文件 3.3.3 创建服务脚本(tomcat.service) 3.3.4 重新加载守护进程并且测试 四、部…...

Unity Shader:常用的C#与shader交互的方法

俗话说久病成医&#xff0c;虽然不是专业技术美术&#xff0c;但代码写久了自然会积累一些常用的shader交互方法。零零散散的&#xff0c;总结如下&#xff1a; 1&#xff0c;改变UGUI的材质球属性 有时候我们需要改变ui的一些属性&#xff0c;从而实现想要的效果。通常UGUI上…...

luajit 使用 clang编译的坑

为了尝试将LuaJIT接入虚幻Lua插件之中&#xff0c;需要预编译LuaJIT链接库&#xff0c;在桌面平台问题不大, 主要是移动平台&#xff0c;涉及跨平台编译&#xff0c;因为对跨平台编译具体细节没有系统研究&#xff0c;这里先记录一下跨平台编译LuaJIT的主要过程 由于官方提供的…...

[SWPUCTF 2021 新生赛]Do_you_know_http

打开环境&#xff0c;根据题目提示&#xff0c;应该是考察http相关的东西 打开环境提示说请使用wLLm浏览器访问 那我们更改浏览器信息&#xff0c;在burp重发器中发包后发现是302重定向&#xff0c;但是提示说success成功&#xff0c;说明 我们修改是成功的&#xff0c;既然是…...

web前端之CSS

文章目录 一、CSS简介1.1 CSS语法规则 二、CSS的引用方法2.1 定义行内样式表2.2定义内部样式表2.3链入外部样式表2.4导入外部样式表 三、CSS选择符3.1 基本选择符3.1.1 标签选择符3.1.2 class类选择符3.1.3 id选择符 3.2 复合选择符3.2.1 交集选择符&#xff08;合并选择器&…...

HarmonyOS元服务开发实践:桌面卡片字典

一、项目说明 1.DEMO创意为卡片字典。 2.不同卡片显示不同内容&#xff1a;微卡、小卡、中卡、大卡&#xff0c;根据不同卡片特征显示同一个字的不同内容&#xff0c;基于用户习惯可选择喜欢的卡片。 3.万能卡片刷新&#xff1a;用户点击卡片刷新按钮查看新内容&#xff0c;同时…...

xLua学习

xLua教程&#xff1a;https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua%E6%95%99%E7%A8%8B.md xLua配置&#xff1a;https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md FAQ&#xff1a;https://github.com/Tencent/xLua/blob/maste…...

​Web3到底是个啥?

Web3到底是个啥&#xff1f; Web3是近两年来科技领域最火热的概念之一&#xff0c;但是目前对于Web3的定义却仍然没有形成标准答案&#xff0c;相当多对于Web3的理解&#xff0c;都是建立在虚拟货币行业&#xff08;即俗称的“币圈”&#xff09;的逻辑基础之上的。 区块链服务…...

pycharm、idea、golang等JetBrains其他IDE修改行分隔符(换行符)

文章目录 pycharm、idea、golang系列修改行分隔符我应该选择什么换行符JetBrains IDE&#xff0c;默认行分隔符 是跟随系统修改JetBrains IDE&#xff0c;默认行分隔符 pycharm、idea、golang系列修改行分隔符 一般来说,不同的开发环境和项目对换行格式的使用偏好不同: Windo…...

ThinkPHP函数深度解析

ThinkPHP是一个具有丰富功能和强大灵活性的PHP开发框架。在这篇文章中&#xff0c;我们将详细介绍ThinkPHP的一些关键函数&#xff0c;以帮助开发人员更好地理解和使用这个框架。 1. 入门&#xff1a;ThinkPHP的核心函数 1.1 C()函数 C()函数用于读取和设置配置参数。它是Thin…...

【java】【maven】【高级】MAVEN聚合继承属性等

目录 1、模块开发与设计 2、聚合 2、继承 3、属性 4、版本管理 5、资源配置 6、多环境配置 7、多环境开发配置 8、跳过测试 9、私服 前言&#xff1a;maven的高级使用包含分模块开发与设计、聚合、继承、属性、版本管理、资源配置、多环境配置、多环境开发配置、跳过…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...