C++ 学习笔记——九、友元、异常和其他
迪丽瓦拉
2025-05-29 02:41:39
0

一、友元

1. 友元类

类并非只能拥有友元函数,也可以将类作为友元,这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员:

class Tv {...
public:friend class Remote;  // 友元类enum {TV, DVD};...
};class Remote {...
public:Remote(int m = Tv::TV) : mode(m) {}...
};

友元类可以位于共有、私有或保护部分,由于 Remote 类提到了 Tv 类,所以编译器必须了解 Tv 类后,才能处理 Remote 类,为此,最简单的方法是首先定义 Tv 类。

2. 友元成员函数

对于上一个例子,Remote 类可能直接访问 Tv 类成员的情况很少,假设只有一个函数 set_chan() 访问了 Tv 成员,那么更高效的方式是将 Remote 的成员函数作为 Tv 的友元函数:

class Tv {friend void Remote::set_chan(Tv & t, inc);
};

然而,要使编译器能够处理这条语句,它必须知道 Remote 的定义。这意味着 Remote 的定义需要放到 Tv 之前,但又因为 Remote 的方法提到了 Tv 对象,因此产生了循环依赖,解决这个问题方法需要前向声明(forward declaration),需要在 Remote 定义的前面插入语句:

// 可行的声明顺序
class Tv;  // 前向声明
class Remote {...};
class Tv {...};// 不可行的声明顺序
class Remote;  // 前向声明
class Tv {...};
class Remote {...};

第二种情况不可行的原因是编译器在 Tv 类的声明中看到 Remote 的一个方法被声明为 Tv 类的友元之前,应该先看到 Remote 类的声明和 set_chan() 方法的声明。

但是第二种方式还存在一个问题,由于 Remote 声明中包含了内联代码:

void onoff(Tv & t) {t.onoff();}

由于此处调用 Tv 的一个方法,因此编译器必须已经看到 Tv 类的声明,这样才能知道 Tv 有哪些方法,因此还是应当采用第一种顺序。

3. 其他友元关系

友元类不但可以单向,也可以双向,即让两个类彼此称为友元类,此时由于互相调用的关系,最好使用前向声明对两个类进行声明。

4. 共同的友元

有时函数需要同时访问两个类的私有数据,但它不能同时是两个类的成员函数,此时将一个函数设置为两个类的友元更为合理。

二、嵌套类

三、异常机制

四、RTTI

运行阶段类型识别:RTTI(Runtime Type Identification),是 C++ 的新特性,旨在为程序在运行阶段确定对象的类型提供一种标准方式。

假设有一个类层次结构,其中的类都是从同一个基类派生而来,则可以让基类指针只想其中任何一个类的对象,这样便可以调用这样的函数:在处理一些信息后,选择一个类,并创建这种类型的对象,然后返回它的地址,而该地址可以被赋给基类指针,那么如何知道指针指向的是哪种对象?

1. RTTI 的工作原理

C++ 有 3 个支持 RTTI 的元素:

  • dynamic_cast 运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则返回空指针;
  • typeid 运算符返回一个指出对象的类型的值;
  • type_info 结构存储了有关特定类型的信息。

只能将 RTTI 用于包含虚函数的类层次结构,原因在于只有对于这种类层次结构,才应该将派生对象的地址赋给基类指针。

Ⅰ. dynamic_cast

dynamic_cast 运算符是最常用的 RTTI 组件,它不能回答“指针指向的是哪类对象”,但能够回答“是否可以安全地将对象的地址赋给特定类型的指针”:

Grandpa * pg = new Grandpa;
Dad * pd = new Dad;
Son * ps = new Son;
Son * p1 = (Son*) ps;  // 安全,ps为Son,p1也是Son
Son * p2 = (Son*) pg;  // 非法,pg是Grandpa,p2是Son,不能用儿子代替老子
Dad * p3 = (Son*) ps;  // 安全,ps为Son,p3为Dad,可以用老子代替儿子
Dad * pm = dunamic_cast(pg);  // 用法,若安全则返回对象地址,若不安全则返回空指针

Ⅱ. typeid 运算符和 type_info 类

typeid 运算符能够确定两个对象是否为同种类型,与 sizeof 相似,可以接受两种参数:

  • 类名;
  • 结果为对象的表达式。

返回一个对 type_info 对象的引用,为 typeinfo 头文件中的一个类,他重载了 == 和 != 运算符,以便可以比较类型:

typeif(Son) == typeid(*son)  // 返回true

typeinfo 类包含一个 name() ,该函数返回一个随实现而异的字符串,通常是类的名称:

cout << typeid(*pg).name();

五、类转换运算符

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...