深蓝学院C++基础与深度解析笔记 第 12 章 类进阶

news2024/11/28 14:42:25

深蓝学院C++基础与深度解析笔记 第 12 章 类进阶

1. 运算符重载

● 使用 operator 关键字引入重载函数:

– 重载不能发明新的运算,不能改变运算的优先级与结合性,通常不改变运算含义
– 函数参数个数与运算操作数个数相同,至少一个为类类型
– 除 operator() 外其它运算符不能有缺省参数
– 可以选择实现为成员函数与非成员函数
   ● 通常来说,实现为成员函数会以 *this 作为第一个操作数(注意 ==<=> 的重载)

● 根据重载特性,可以将运算符进一步划分参考资料:

– 可重载且必须实现为成员函数的运算符( =,[],(),-> 与转型运算符)
– 可重载且可以实现为非成员函数的运算符,(理论上都可以)
– 可重载但不建议重载的运算符( &&, ||, 逗号运算符)
    ● C++17 中规定了相应的求值顺序(之前没有规定求值顺序),但没有方式实现短路逻辑
– 不可重载的运算符(如 ? : 运算符)

C++中不可重载的运算符列表总结:

  • 作用域解析运算符 ::
  • 成员指针运算符 .*
  • 成员对象指针运算符 ->*
  • 条件运算符(三元运算符) ?:
  • 大小运算符 sizeof
  • 成员选择运算符 .(点操作符)
  • 成员访问运算符 .*(星号点操作符)
  • 对象创建和销毁运算符 new 和 delete
  • 对象创建和销毁运算符 new[] 和 delete[]
  • 对象创建和销毁运算符 ::new 和 ::delete
  • 对象创建和销毁运算符 ::new[] 和 ::delete[]
  • 运行时类型信息运算符 typeid
  • 数组下标访问运算符 []
  • 函数调用运算符 ()

● 对称运算符通常定义为非成员函数以支持首个操作数的类型转换
● 移位运算符一定要定义为非成员函数,因为其首个操作数类型为流类型
● 赋值运算符也可以接收一般参数
● operator [] 通常返回引用
● 自增、自减运算符的前缀、后缀重载方法,括号内为空为前缀++:
在这里插入图片描述
后缀:
在这里插入图片描述
后缀比前缀会有更大开销,但是编译器可能会优化掉,不保证优化掉

● 使用解引用运算符( * )与成员访问运算符( -> )模拟指针行为

  – 注意“ .” 运算符不能重载
  – “→” 会递归调用 操作 “→”

opreater这只能返回:1、另外的一个类 或结构体 2、另外的一个类 或结构体指针
● 使用函数调用运算符构造可调用对象:
指在C++中,可以通过重载函数调用运算符(operator())来创建一个可调用对象,使其表现得像一个函数一样。

#include <iostream>

class MyCallable {
public:
    void operator()(int value) const { // 重载了函数调用运算符 operator()
        std::cout << "Called with value: " << value << std::endl;
    }
};

int main() {
    MyCallable myObj;
    myObj(42);  // 使用函数调用运算符调用对象
    return 0;
}

通过函数调用运算符的重载,我们可以自定义可调用对象的行为,使其在使用时更加灵活和符合特定需求。这种方式可以用于函数对象、函数指针、Lambda 表达式等各种类型的可调用实体。

● 类型转换运算符

– 函数声明为 operator type() const ,通常会加const
– 与单参数构造函数一样,都引入了一种类型转换方式
– 注意避免引入歧义性与意料之外的行为
   ● 通过 explicit 引入显式类型转换, 只能通过显式调用来进行类型转换的构造函数。
– explicit bool 的特殊性:用于条件表达式时会进行隐式类型转换

● C++ 20 中对 == 与 <=> 的重载

– 通过 == 定义 !=, 反之不行
– 通过 <=> 定义多种比较逻辑
– 隐式交换操作数
– 注意 <=> 可返回的类型: strong_ordering, week_ordering, partial_ordering

2. 类的继承

● 通过类的继承(派生)来引入 是一个 的关系:(is - a,抽象不断具体化)
在这里插入图片描述

– 通常采用 public 继承( struct V.S. class )
– 注意:继承部分不是类的声明,声明不加继承方式,加了报错 
– 使用基类的指针或引用可以指向派生类对象
– 静态类型 V.S. 动态类型
– protected 限定符:派生类可访问

使用基类的指针或引用可以指向派生类对象:
在这里插入图片描述

● 类的派生会形成嵌套域:

– 先构造基类,再构造子类
– 派生类所在域位于基类内部
– 派生类中的名称定义会覆盖基类
– 使用域操作符显式访问基类成员 
– 在派生类中(含派生类的构造函数)调用基类的构造函数

● 通过虚函数与引用(指针)实现动态绑定

– 使用关键字 virtual 引入
– 非静态、非构造函数可声明为虚函数
– 虚函数会引入vtable结构
   ● dynamic_cast

示意图:
在这里插入图片描述

● 虚函数在基类中的定义

– 引入缺省逻辑
– 可以通过 = 0 声明纯虚函数,相应地构造抽象基类 ,可以但是不建议

● 虚函数在派生类中的重写( override )

– 函数签名保持不变(返回类型可以是原始返回指针 / 引用类型的派生指针 / 引用类型)
– 虚函数特性在子类中保持不变
– override 重写 关键字   final不再重写关键字

● 由虚函数所引入的动态绑定属于运行期行为,与编译期行为有所区别

  – 虚函数的缺省实参只会考虑静态类型,编译期就完成了
  – 虚函数的调用成本高于非虚函数
      ● final 关键字**
  – 为什么要使用指针(或引用)引入动态绑定
  – 在构造函数中调用虚函数要小心
  – 派生类的析构函数会隐式调用基类的析构函数
  – 通常来说要将基类的析构函数声明为 virtual 的
  – 在派生类中修改虚函数的访问权限

2. 类的继承——继承与特殊成员函数

● 派生类合成的……

– 缺省构造函数会隐式调用基类的缺省构造函数
– 拷贝构造函数将隐式调用基类的拷贝构造函数
– 赋值函数将隐式调用基类的赋值函数

● 派生类的析构函数会调用基类的析构函数
● 派生类的其它构造函数将隐式调用基类的缺省构造函数
● 所有的特殊成员函数在显式定义时都可能需要显式调用基类相关成员
● 构造与销毁顺序

– 基类的构造函数会先调用,之后才涉及到派生类中数据成员的构造
– 派生类中的数据成员会被先销毁,之后才涉及到基类的析构函数调用

补充知识:
● public 与 private 继承参考资料

public 继承:描述 是一个 的关系 “ ”;子类和父类的权限是一致的
– private 继承:描述 根据基类实现出 的关系 “ ”, 仅类内部可见
– protected 继承:几乎不会使用,基类

● using 与继承

– 使用 using 改变基类成员的访问权限
  ● 派生类可以访问该成员
  ● 无法改变构造函数的访问权限
– 使用 using 继承基类的构造函数逻辑
– using 与部分重写

● 继承与友元:友元关系无法继承,但基类的友元可以访问派生类中基类的相关成员;友元是单向的
● 通过基类指针实现在容器中保存不同类型对象,可以放置子类的类型
● 多重继承与虚继承 :将继承的访问方式改成 virtual
● 空基类优化 与 [no_unique_address] 属性 :

当派生类继承一个空基类时,根据空基类优化,编译器可以选择不为派生类分配额外的空间来存储空基类的对象。相反,派生类可以共享基类的内存空间,从而减少派生类对象的总体大小。

[[no_unique_address]]属性是C++ 20 标准提供的一种属性(attribute),用于指示编译器在内存布局中不分配额外的空间来存储特定的成员变量。它可以应用于非静态数据成员,包括非静态数据成员的嵌套。
使用[[no_unique_address]]属性有助于减小类的大小,尤其是在存在多个成员变量且某些成员变量具有相同类型且不需要独立的地址时。这种情况下,编译器可以选择共享存储空间,从而减少对象的总体大小。

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

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

相关文章

C++模拟实现unordered_map和unordered_set(哈希)

目录 一、unordered系列关联式容器 1.1 unordered_map 1.1.1 unordered_map 1.1.2 unordered_map接口说明 1. unordered_map的容量 2. unordered_map的迭代器 3.unordered_map的元素访问 4. unordered_map的查询 5. unordered_map的修改操作 6. unordered_map的桶操作…

ros::catkin_create_pkg

用下面的命令即可 catkin_create_pkg first_pkg rospy roscpp std_msg -m ur-email-name

HBase(一)HBase v2.2 高可用多节点搭建

最近刚刚完成了HBase相关的一个项目,作为项目的技术负责人,完成了大部分的项目部署,特性调研工作,以此系列文章作为上一阶段工作的总结. 前言 其实目前就大多数做应用的情况来讲,我们并不需要去自己搭建一套HBase的集群,现有的很多云厂商提供的服务已经极大的方便日常的应用使…

接口测试工具——Postman使用详解

目录 Postman简介 Postman主界面 菜单栏 工具栏 请求管理区 环境管理区 请求设计区 发送请求 发送GET请求 Postman发送GET请求 发送表单格式POST请求 发送JSON格式POST请求 发送XML格式POST请求 发送文件上传类型的请求 响应 环境和变量 环境变量设置 环境变量…

【Ceph的介绍】

目录 1、存储基础1、单机存储设备2、单机存储的问题3、商业存储解决方案4、分布式存储&#xff08;软件定义的存储 SDS&#xff09;1、分布式存储的类型 2、Ceph 简介3、Ceph 优势4、Ceph 架构5、Ceph 核心组件1、Pool中数据保存方式支持两种类型2、Pool、PG 和 OSD 的关系 6、…

测试用例设计方法-场景法详解

01、定义 场景法是通过运用场景来对系统的功能点或业务流程的描述&#xff0c;从而提高测试效果的一种方法。 场景法一般包含基本流和备用流&#xff0c;从一个流程开始&#xff0c;通过描述经过的路径来确定的过程&#xff0c;经过遍历所有的基本流和备用流来完成整个场景。…

SOPC之NiosⅡ系统(四)

NIOS Ⅱ系统实例&#xff0c;参考自特权同学《勇敢的芯-伴你玩转NIOS Ⅱ》 一些基础操作就不再赘述 目录 1.创建Quartus项目 1.2 进入Platform Designer添加组件并设置 1.2.1 设置时钟频率50MHz&#xff1b; 1.2.2 添加Nios Ⅱ组件 1.2.3 添加RAM组件 1.2.4 设置Nios Ⅱ…

【每日随笔】摩托车安全驾驶 ① ( 摩托车骑行准备 | 买好保险 | 摩托车必要改装 - 护杠 + 行车记录仪 | 骑行护具 )

文章目录 一、摩托车骑行准备1、买好保险2、摩托车必要改装 - 护杠 行车记录仪3、骑行护具 德州考驾照归来 , 提了一辆 铃木 UY125 , 注意安全驾驶 , 以后上班就骑摩托车了 ; 由于居住证上的地址是海淀区 , 目前住在学院路 , 导致无法把车落户到自己名下 , 只能上公户了 ; 车…

G1垃圾收集器-JVM(十三)

上篇文章说了CMS垃圾收集器使用以及三色标记如何解决cms的一些问题。分别有初始标记&#xff0c;并发标记&#xff0c;重新标记&#xff0c;并发清理&#xff0c;并发重置。 CMS垃圾收集器&三色标记-JVM&#xff08;十二&#xff09; G1收集器&#xff08;Garbage-First&a…

浅析缓存一致性的解析方案

各位同学们平时开发的时候除了使用到数据库&#xff08;这里以mysql为例&#xff09;还会用到相关的缓存&#xff08;这里以redis为例&#xff09;操作。 举一个常用的场景当我们写的接口性能相对比较慢的时候&#xff08;高并发场景需要响应速度很快&#xff09;为了保证性能的…

LeetCode144. 二叉树的前序遍历

144. 二叉树的前序遍历 文章目录 [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/)一、题目二、思路及代码&#xff08;1&#xff09;递归&#xff08;2&#xff09;迭代&#xff08;两种方法&#xff09; 一、题目 给你二叉树的根节点…

AlienSwap 首期 Launchpad — 偶像女团 NFT+RWA 的创新探索

NFT 是整个加密市场一致看好&#xff0c;并认为会继续爆发的领域。随着更多的 NFT 平台和 NFT 项目的推出&#xff0c;NFT 市场的格局也在不断变化。从开始的 OpenSea 占据绝对领先地位&#xff0c;到 Blur 的横空出世风头无两&#xff0c;在加密领域&#xff0c;局势更迭总是在…

【Java面试丨并发编程】线程中并发安全

一、Synchronized关键字的底层原理 1. Synchronized的作用 Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】&#xff0c;其他线程再想获取这个【对象锁】时就会阻塞住 2. Monitor Synchronized【对象锁】底层是由Monitor实现&#xff0c;…

泰裤辣!这是什么操作,自动埋点,还能传参?

目录 前言 参数放在注释中 准备入口文件 编写插件 运行代码 完整代码 参数放在局部作用域中 准备源代码 编写插件 运行代码 完整代码 总结 前言 在上篇文章讲了如何通过手写babel插件自动给函数埋点之后&#xff0c;就有同学问我&#xff0c;自动插入埋点的函数怎么…

基于IMX6ULL的AP3216C的QT动态数据曲线图显示

前言&#xff1a;本文为手把手教学 LinuxQT 的典型基础项目 AP3216C 的数据折线图显示&#xff0c;项目使用正点原子的 IMX6ULL 阿尔法( Cortex-A7 系列)开发板。项目需要实现 AP3216C 在 Linux 系统下的驱动&#xff0c;使用 QT 设计 AP3216C 的数据显示页面作为项目的应用层。…

消息中间件RabbitMQ简介

1.1消息队列中间件简介 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性[架构] 使用较多的消息队列有ActiveMQ&#xff0c;RabbitMQ&#xff…

人工智能安全风险:零信任的作用

人工智能&#xff08;AI&#xff09;和机器学习技术飞速发展&#xff0c;我们所处的时代正在经历前所未有的创新。但是&#xff0c;技术飞速发展的同时也带来了各种挑战。人工智能技术越来越复杂&#xff0c;与之相关的网络安全风险也越来越棘手&#xff0c;随之产生了一个新的…

TortoiseGit 入门指南10:贮藏

有时&#xff0c;当你在项目的一部分上已经工作一段时间后&#xff0c;所有东西都进入了混乱的状态&#xff0c; 而这时你想要切换到另一个分支做一点别的事情。 问题是&#xff0c;你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是贮藏 …

【Linux指令集】---unzip指令(超详细)

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Linux专栏】&#x1f388; 本专栏旨在分享学习Linux的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 演示环境&#xff1…

JVM系统优化实践(19):GC生产环境案例(二)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 接昨天的问题继续来说&#xff0c;在高并发场景中&#xff0c;对象过多容易导致OOM。由于高并发导致Young GC存活对象过多&#xff0c;因此会有太多对象进入老年代&#xf…