C++ 模版和继承

目录

一.模版

1.模版的基本概念

a.函数模版

b.类模板

c.模版的实例化

d.class 和 typename的区别

e.非类型模版参数

2.模版的特化

a.全特化 —— 参数类型全部特殊化处理

b.半特化 —— 部分参数特殊化处理

c.偏特化——对某些类型的进一步限制(实例化时传的也是指针类型)

3.类模版内函数的声明和定义分离

二.继承

1.继承的基本知识

a.继承的方式

b.构造函数和析构函数

2.基类和派生类对象的赋值转换(前提:公有继承)

a.基类对象不能赋值给派生类对象

b. 派生类对象可以赋值给基类对象(切片)

c.使用动态类型转换

3.隐藏/重定义

a.成员函数隐藏

b.成员变量隐藏

三.多继承(重难点)

1.菱形继承

2.虚继承

a.虚继承的底层原理

b.虚基表和虚基表指针

3.继承和组合


一.模版

1.模版的基本概念

C++模板分为函数模板和类模板两种。

a.函数模版

函数模板:定义一个函数,该函数的参数可以是任意类型,当编译器调用该函数时,会根据提供的参数类型自动生成对应的函数实例。

b.类模板

类模板:定义一个类,我们可以向这个类传递任意类型,编译器在创建类的实例时,会根据提供的类型自动生成对应的类定义。

c.模版的实例化

当编译器遇到模板的使用时,它会根据提供的类型参数生成一个特定类型的模板实例,这个过程称为模板的实例化。

例如,在上面的main函数中,当使用Stack<int>时,编译器会生成一个Stack类的实例,其中T被替换为 int。同样地,当使用Stack<string>时,编译器会生成另一个Stack类的实例,其中T被替换为string。

注意:普通类的类名和类型相同,但是对类模版而言,类名是类名,类型是类型,域作用符使用的是类型!!

函数模版实例化如下:

显示实例化

d.class 和 typename的区别

在C++中,class 和 typename 都可以用于在模板定义中指定类型参数,但它们之间实际上没有功能性的区别。这两个关键字在模板参数列表中是可以互换使用的,用来指示随后的标识符是一个类型名称。

但是,当我们使用域作用访问限定符去访问类中的某个数据类型时,typename 的作用就显现出来了,示例如下:

只要使用没被实例化的模板类里面的typedef后的数据类型,都要在前面加一个typename,否则编译器报错!!

e.非类型模版参数

非类型模板参数指的是模板参数列表中不是类型参数的部分,它们可以是整数常量表达式、指针类型(指向对象或函数的指针,但通常指向对象的指针更常用)以及引用类型

如图:

注意:

①非类型模板参数必须是编译时常量

②对于整数类型的非类型模板参数,它们可以是有符号或无符号的整数类型,包括char、short、int、long以及它们的无符号版本。

③指针和引用类型的非类型模板参数必须指向或引用有效的对象或函数,并且这些对象或函数在模板实例化时必须是可访问的。

2.模版的特化

模板特化是一种对模板进行定制化的技术,它允许我们为模板的某个特定类型或值提供专门的实现。模板特化分为完全特化和半特化,但注意,对于函数模板来说,只有完全特化,没有半特化。

a.全特化 —— 参数类型全部特殊化处理

当模板实例化时,如果使用了与特化相匹配的类型或值,则编译器会使用特化的版本而不是通用的模板版本。

b.半特化 —— 部分参数特殊化处理

部分特化(仅适用于类模板)允许我们为模板的某些类型参数提供特定的实现,同时保留其他类型参数的通用性

c.偏特化——对某些类型的进一步限制(实例化时传的也是指针类型)

3.类模版内函数的声明和定义分离

情景:我们在vector.h文件内对类模板内成员函数做出声明,在vector.cc文件内对模版类内函数做出定义,在test.cc文件内对类模版进行实例化,编译时出现链接报错,为什么??

---由于编译器对各源文件的编译在“链接”前都是无交织状态的,导致类内的模版函数在其他外部文件内定义时无法收到来自源文件传来的模版参数无法完成模版参数的实例化,而涉及模版的东西,都是完成实例化后才能生成地址,所以在“链接”时,其它源文件就找不到模版函数定义的位置,最终报错!!

解决方法:

a.显示实例化——在其它源文件内声明 template class stack<int>;  //但是这种方法限制了模版的作用,传入int类型,就会限制其它类型数据对该类的使用

b.将模版函数的定义放在类的同一个文件内。

c.将模版函数定义所在的文件,包含在使用该类的源文件内。

二.继承

1.继承的基本知识

情景:结构体和类里面的属性数据都是一样的,而在某些特定的场景下,需要所有人既要有这些共性属性,又要有一些个性化的属性。如:同一个班级内的学生,它们的:学校名、学院名、专业名、班级名...都是一样的,但像:学号、姓名、身份证号...等信息又都是不一样的。在这样的场景下,就不能用一个共有的结构体去描述学生的属性数据,这时,我们可以创建一个描述公共属性数据的结构体(基类),然后用个性化的结构体(派生类)去继承它

什么是继承?--- 继承是一种面向对象编程的特性,它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法。通过这种方式,派生类可以重用基类的代码,并且可以添加新的属性和方法或者覆盖基类的方法。

a.继承的方式

公共继承:基类的公共成员在派生类中也是公共的,基类的保护成员在派生类中也是保护的。

保护继承:基类的公共成员在派生类中变为保护的,基类的保护成员在派生类中仍然是保护的。

私有继承:基类的公共成员和保护成员在派生类中都是私有的。

注意:①基类的私有成员在派生类中都是不可见的;②基类的公有成员在派生类中的权限类型是由继承的方式决定的。

b.构造函数和析构函数

构造函数:当创建派生类的对象时,首先会调用基类的构造函数。因此,如果基类有构造函数,那么派生类也需要显式地调用它(通过初始化列表)

析构函数:当派生类的对象被销毁时,首先会调用派生类的析构函数,然后是基类的析构函数。

继承到的基类成员变量的声明是在派生类成员变量之前的,即基类的成员变量在初始化列表要先于派生类成员变量完成初始化!

派生类的拷贝构造给基类成员变成初始化时,若不显示传参,则调用基类的默认构造;若显示传参,则调用基类的拷贝构造。

派生类的赋值重载内,对基类成员变量完成赋值时,需要显示调用基类的赋值重载,这里需要注意“由于函数名相同,导致隐藏问题”,需指定类域!

注意:继承时,若不指定继承方式,则默认是私有继承!!

2.基类和派生类对象的赋值转换(前提:公有继承)

a.基类对象不能赋值给派生类对象

派生类对象包含了基类对象的所有成员,但还可能包含额外的成员。因此,将一个基类对象赋值给一个派生类对象会导致信息丢失或不一致,这是不允许的。

b. 派生类对象可以赋值给基类对象(切片)

派生类对象可以被赋值给基类对象,但这种情况下会发生对象切片,即派生类对象中特有的成员会被丢弃,只保留基类部分的成员。

注意切片和强制类型转换的区别:

与其它不同类型对象间的赋值规则(强制类型转换)不一样,派生类对象赋值给基类对象的过程,*不会产生临时对象,而是“赋值兼容转换”,类似“切割,切片”,即将子类对象中与父类对象重合的数据直接拷贝赋值给父类对象。

c.使用动态类型转换

在运行时,如果需要安全地将基类指针或引用转换为派生类指针或引用,可以使用dynamic_cast。如果转换失败,dynamic_cast会返回nullptr(对于指针)或抛出异常(对于引用)。

3.隐藏/重定义

"隐藏"通常指的是在继承关系中,派生类的成员函数或变量与基类中的同名成员发生冲突时,导致基类中的成员被隐藏。在派生类内,使用相同的成员名时,默认访问的是派生类自己的成员数据,而若想指定使用基类的成员,则需使用域作用访问限定符

隐藏分为两种:成员函数隐藏成员变量隐藏

a.成员函数隐藏

如果派生类中定义了一个与基类成员函数同名的成员函数(即使参数列表不同),基类的成员函数在派生类的作用域内会被隐藏。

对成员函数而言,只要基类和派生类的成员函数名相同,无论参数如何,二者不构成函数重载,而构成“隐藏”关系!!

b.成员变量隐藏

如果派生类中定义了一个与基类成员变量同名的成员变量,基类的成员变量在派生类的作用域内会被隐藏。

注意隐藏成员的访问格式:d.Base::func();    d.Base::value; 

由于多态,析构函数的函数名都会被特殊处理,统一处理成了destructor,导致基类的析构与派生类的析构形成“隐藏”关系,所以在派生类的析构内必须指定类域去调用基类的析构函数,但是为了保证析构顺序“先子后父”,编译器会特殊处理基类成员变量的析构,即调用完派生类的析构后,编译器会自动帮我们调用基类的析构,这样一来,我们对基类成员的消耗不必理会即可。

注意:①基类的友元函数不能继承给派生类;②派生类能够继承基类中的静态成员,与基类“共享”静态成员。

三.多继承(重难点)

一个子类继承两个或两个以上的父类时,这个继承关系称为“多继承”。如:class Assistant : public  Student, public  Teacher {}

示例如下:

1.菱形继承

菱形继承是指一个类从多个基类继承,而这些基类又共同继承自另一个基类。这可能导致数据冗余和二义性问题,因为派生类会有多个路径访问同一个基类成员

上述的D类相当于间接的继承了两次A类,导致_d中含有两个_a成员变量,那么,我们该如何解决这种问题呢?换句话说,菱形继承所带来的数据二义性该如何解决?--- 虚继承!!

2.虚继承

通过在中间基类(即那些被多个基类继承的基类)的继承声明中使用 virtual 关键字,可以确保派生类只继承一个基类实例。这样,无论派生类通过哪条路径继承,它都只会看到一个基类实例。

a.虚继承的底层原理

虚继承的底层原理,菱形虚拟继承中各成员变量在内存中的排布:

好的,现在让我们来解释一下虚继承的底层原理,以及B和C中的那两个指针又是怎么回事儿~~

在编译器编译时,对于虚继承的派生类(如类B和类C),编译器会在其对象中添加一个指向虚基类实例的指针(虚基表指针),这个指针用于指向虚基类的唯一实例。

在派生类中,对于虚基类的成员访问都通过这个虚基类指针进行。这样,无论派生类通过哪个路径继承虚基类,都可以通过这个指针访问到虚基类的唯一实例,从而避免了菱形继承中的二义性问题。

b.虚基表和虚基表指针

虚基表指针通常在虚继承类成员变量的前面,指向类的虚基表,虚基表是因虚继承产生的,表内存放的是“虚基表指针的地址”与派生类继承的“基类成员变量”的偏移量,可通过 虚基表指针+表内偏移量 的方式找到派生类所继承的基类成员变量的位置!

多个虚继承类对象共用一个偏移量表(虚基表),偏移量的存在保证了“切割”时对数据的成功读取。

虚继承的类,其成员变量在内存中的存储也会发生改变,所继承的基类成员变量在内存中,以指针的形式指向一个偏移量表,其内记录了基类成员在内存中与该指针的相对偏移位置。

注意:成员变量在内存地址方面的存储,基类成员且先继承的在最前面!虚拟继承对基类成员的初始化的顺序是由类声明的顺序决定的!

3.继承和组合

继承是面向对象编程中的一个基本概念,它允许一个类继承另一个类的属性和方法。继承主要用于表示“是一种”(is-a)的关系。

组合是一种将一个类的对象作为另一个类的成员的方式。组合用于表示“有一个”(has-a)的关系。

继承:class D : public C{};     组合:   class E {  private : C _cc; };

在继承方式中,基类的内部细节对派生类可见,继承在一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响,派生类与基类间耦合度较高。

而基类中protected的成员仍能被派生类继承,但无法被组合类使用,这在一定程度上降低了基类与组合类间的耦合度

而组合类之间没有很强的依赖关系,耦合度低,优先使用对象组合有助于我们保持每个类被封装。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GD32学习知识点累计

时钟系统 GD32f427主频最高位240MHZ&#xff08;但是只能到200M&#xff09;&#xff0c;GD32给的函数外接25MHZ晶振配置主频为200MHZ,APB1最高频率为60HZ配置为主频的4分频为50MHZ&#xff0c;APB2最大为120MHZ配置为主频的2分频为100MHZ 定时器 无论什么定时器最大频率为200M…

安全见闻---清风

注&#xff1a;本文章源于泷羽SEC&#xff0c;如有侵权请联系我&#xff0c;违规必删 学习请认准泷羽SEC学习视频:https://space.bilibili.com/350329294 安全见闻1 泷哥语录&#xff1a;安全领域什么都有&#xff0c;不要被表象所迷惑&#xff0c;无论技术也好还是其他方面…

AI带货主播框架的搭建!

AI带货主播&#xff0c;作为新兴的技术应用&#xff0c;正在逐渐改变电商行业的面貌&#xff0c;通过利用人工智能技术&#xff0c;AI带货主播能够模拟真实主播的行为&#xff0c;与用户进行互动&#xff0c;推荐商品&#xff0c;提升购物体验。 本文将介绍如何搭建一个AI带货…

处理Hutool的Http工具上传大文件报OOM

程序环境 JDK版本&#xff1a; 1.8Hutool版本&#xff1a; 5.8.25 问题描述 客服端文件上传主要代码&#xff1a; HttpRequest httpRequest HttpUtil.createPost(FILE_UPLOAD_URL); Resource urlResource new UrlResource(url, fileName); httpRequest.form("file&q…

self-supervised learning(BERT和GPT)

1芝麻街与NLP模型 我們接下來要講的主題呢叫做Self-Supervised Learning&#xff0c;在講self-supervised learning之前呢&#xff0c;就不能不介紹一下芝麻街&#xff0c;為什麼呢因為不知道為什麼self-supervised learning的模型都是以芝麻街的人物命名。 因為Bert是一個非常…

实战-任意文件下载

实战-任意文件下载 1、开局 开局一个弱口令&#xff0c;正常来讲我们一般是弱口令或者sql&#xff0c;或者未授权 那么这次运气比较好&#xff0c;直接弱口令进去了 直接访问看看有没有功能点&#xff0c;正常做测试我们一定要先找功能点 发现一个文件上传点&#xff0c;不…

中酱集团:黑松露酱油,天然配方定义健康生活

在如今的大健康时代&#xff0c;人们对于美食的要求越来越高。不仅美味&#xff0c;更要健康。在健康美食的生态链中&#xff0c;有一个名字正逐渐成为品质与美味的代名词——中酱集团。而当中酱集团与黑松露酱油相遇&#xff0c;一场味觉的革命就此拉开帷幕。 中酱集团&#x…

【产品应用】旋转式贴标机一站式解决方案

针对贴标机行业设备&#xff0c;立迈胜公司拥有智能控制器、一体化伺服电机、减速机等系列产品&#xff0c;可以轻松解决传统电机接线不便、占用空间、自重过大、部件繁杂等问题&#xff0c;帮助贴标机制造商实现设备精准控制、运行稳定的同时&#xff0c;保证生产流程高效产出…

开发运维警示录-20241024

开发警示录 1、作为开发&#xff0c;不要私自修改业务人员给的SQL语句&#xff0c;虽然个人感觉SQL很冗余&#xff0c;效率低等。 2、开发前&#xff0c;要明确需求&#xff0c;必要时通过图和文字形成文档与需求方确认、留痕。 3、开发复杂的业务逻辑代码前&#xff0c;先疏通…

oracle数据库---PL/SQL、存储函数、存储过程、触发器、定时器job、备份

PL/SQL 什么是 PL/SQL PL/SQL&#xff08;Procedure Language/SQL&#xff09;是 Oracle 对 sql 语言的过程化扩展&#xff0c;指在 SQL 命令语言中增加了过程处理语句&#xff08;如分支、循环等&#xff09;&#xff0c;使 SQL 语言具有过程处理能力。把SQL语言的数据操纵能…

瑞芯微的 展会总结

首先是我感兴趣的产品&#xff1a; 摄像头的 墨水瓶的。 android 盒子&#xff0c;使用的是rk3588s 然后是瑞芯微&#xff21;&#xff29;在做什么&#xff1a;  在对 音频 视屏的输出 进行补充。 比如&#xff0c;视频拍了一张图片很模糊&#xff0c;那么他们用AI算法&am…

基于Multisim红外接近报警电路设计(含仿真和报告)

【全套资料.zip】红外接近报警电路设计Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 标题&#xff1a;红外接近报警电路 红外报警器是当前利用电子技术制作而成的防盗报警器&#xff0c…

Sei 生态迎首个 MMORPG 游戏伙伴 Final Glory,开启新篇章

​“随着 Final Glory 拓展至 SEI Network&#xff0c;SEI 生态也迎来了首款 MMORPG 游戏” 链游赛道新贵 Final Glory Final Glory 是建立在 MateArena 引擎上的 MMORPG 游戏&#xff0c;作为目前行业内首个斥巨资打造的 AAA 级 MMORPG 全链游戏&#xff0c;在面向市场后即引发…

PostgreSQL两节点用keepalived实现主备的高可用架构

使用keepalived实现PostgreSQL数据库两节点主备的高可用架构部署详解 环境配置和规划部署PostgreSQL的主备流复制架构keepalived介绍安装部署keepalived数据库配置配置keepalived相关参数文件启动keepalived模拟故障切换问题记录实践建议 看腻了就来听听视频演示吧&#xff08;…

Java 多线程(八)—— 锁策略,synchronized 的优化,JVM 与编译器的锁优化,ReentrantLock,CAS

前言 本文为 Java 面试小八股&#xff0c;一句话&#xff0c;理解性记忆&#xff0c;不能理解就死背吧。 锁策略 悲观锁与乐观锁 悲观锁和乐观锁是锁的特性&#xff0c;并不是特指某个具体的锁。 我们知道在多线程中&#xff0c;锁是会被竞争的&#xff0c;悲观锁就是指锁…

LSTM反向传播及公式推导

先回顾一下正向传播的公式: 化简一下: 反向传播从下到上逐步求偏导: 对zt求偏导(预测值和标签值相减): zt对未知数wt,ht,bt分别求偏导: ht对ot,Ct求偏导: ot对Net0求偏导: Net0对w0,b0求偏导: .... 总体的思路就是那个公式从下到上逐步对未知数求偏导: 下面是总体的流程…

Flutter项目打包ios, Xcode 发布报错 Module‘flutter barcode_scanner‘not found

报错图片 背景 flutter 开发的 apple app 需要发布新版本&#xff0c;但是最后一哆嗦碰到个报错&#xff0c;这个小问题卡住了我一天&#xff0c;之间的埪就不说了&#xff0c;直接说我是怎么解决的&#xff0c;满满干货 思路 这个报错 涉及到 flutter_barcode_scanner; 所…

微信小程序性能优化 ==== 合理使用 setData 纯数据字段

目录 1. setData 的流程 2. 数据通信 3. 使用建议 3.1 data 应只包括渲染相关的数据 3.2 控制 setData 的频率 3.3 选择合适的 setData 范围 3.4 setData 应只传发生变化的数据 3.5 控制后台态页面的 setData 纯数据字段 组件数据中的纯数据字段 组件属性中的纯数据…

Java.6--多态-设计模式-抽象父类-抽象方法

一、多态 1.定义--什么是多态&#xff1f; a.同一个父类的不同子类对象&#xff0c;在做同一行为的时候&#xff0c;有不同的表现形式&#xff0c;这就是多态。&#xff08;总结为&#xff1a;一个父类下的不同子类&#xff0c;同一行为&#xff0c;不同表现形式。&#xff0…

springboot3.x.x 集成 连接SQL Server 2008 驱动版本和SSL套接字问题的解决

驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client 依赖版本 <dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>mssql-jdbc&…