C++中的继承
面向对象的三大特性
- 封装
- 继承
- 多态
继承的概念和定义
继承的本质就是类层次的复用。
- 继承的概念
- 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段.
它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。
继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
继承是类设计层次的复用
基类(父类) 派生类(子类)
父类就是被继承的类。
子类就是继承的类。
子类复用了父类
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "tongtong"; // 姓名 int _age = 15; // 年龄
};class Student : public Person
{
protected:int _stuid; // 学号
};
int main()
{Student s;//如果共有子类可以用父类的函数//私有就不可以s.Print();return 0;
}
用上面的定义来说,
person就是父类,student就是子类,子类会复用父类
看打印的结果,我们发现,虽然studen没有名字和年龄,但是却可以打印,原因就是继承了
继承关系和访问限定符
class Student : public Person
,
在定义student
的时候其中pubilc
就是继承方式。
继承关系和访问限定符都是有三种,public,protected,private
所以继承关系和访问限定符有9种组合方式,具体如下图。
类成员/继承方式 | pubilc 继承 | protected 继承 | private 继承 |
---|---|---|---|
父类的pubilc 成员 | 子类的pubilc 成员 | 子类的protected 成员 | 子类的private 成员 |
父类的protected 成员 | 子类的protected 成员 | 子类的protected 成员 | 子类的private 成员 |
父类的private 成员 | 在子类中不可见 | 在子类中不可见 | 子类中不可见 |
当在继承的时候,可以不写继承关系。
但是class默认的继承方式是private,struct的继承方式是public。
- 总结
- 访问方式==父类访问限定符和限定方式小的。pubic>protected>private.
- 在父类中,这两个访问限定符没有区别,都是在类中可以访问,在类外不可访问。
但是在子类中,他们两个有区别。
protected
在子类中可见,不可用。
private
在子类中不可见,不可用。
protected
和private
的区别父类和子类的赋值转换
将子类转换为父类,不需要发生类型转换,不会产生临时变量,天然支持的。
可以这样理解,父类是特殊的子类。
int main()
{ //发生隐式类型类型转换double d = 1.5;int i = d;//必须用const,临时变量具有常性const int& i2 = d;//天然支持的,不存在类型转换发生Student s;Person p = s;//没有产生临时对象,所以不用加constPreson p2& = s;Preson* ptr = &s;return 0;
}
如果不理解,可以形象的看这个图。
- 那么问一个问题?
- 父能不能给给子?
不可以,父类的东西比子类的东西少。
继承中的作用域
- 在继承体系中基类和派生类都有独立的作用域。
- 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用
基类::基类成员
显示访问) - 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
- 注意在实际中在继承体系里面最好不要定义同名的成员。
- 问题:既然子类和父类有自己的作用域,那么能不能有同名变量或同名函数?(隐藏/重定义)
- 可以,独立的作用域当然可以拥有同名的变量或函数。
就近原则,优先访问自己作用域,
但是如果想访问同名的其他作用域,指定作用域就可以。
做下面这个练习题
class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" << i << endl;}
};
//A:两个fun构成函数重载
//B:两个fun构成隐藏
//C:编译报错
//D:以上说法都不对
B,
在不同的作用域,不可能构成函数重载,这两个类也没有问题,他们构成隐藏。
有人会想,他们同名,参数不同还构成隐藏吗?
如果是成员函数的隐藏,只需要保证函数名相同就可以。不用考虑参数,和返回值。
如果想用A的fun怎么用?
B().A::fun();
加上域作用限定符就可以,我用的是匿名对象,大家也可以不用。
子类的默认成员
先考虑默认成员函数
先给大家一个父类,写一个
student
子类
class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person & p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};
1、子类的构造函数
父类的成员必须调用父类的构造进行初始化。如果在子类中不写构造和析构函数,调用父类的构造函数和析构函数。
父类的成员调用父类的构造函数初始化,子类的自己的成员自己初始化,
用到方法就是在初始化列表中,按照这个方式初始化person(name)
,调用父类的构造,用我们自己传的参数构造。
如果不写person(name)
,也会调用父类的构造函数,用缺省参数构造。
我们可以这样理解,将父类当成子类的成员。
class Student : public Person
{Student(const char* name,int num):Person(name)//规定这么写,调用父类的构造函数初始化//如果不写person(name)也可以调用父类的构造函数。,_num(num){}
protected:int _num;
};
int main()
{Student s("tongtong",20);return 0;
}
2、子类的拷贝构造
如果不写子类的拷贝构造,会调用父类的默认的拷贝构造。
class Student : public Person
{
public:Student(const Student& s){}
protected:int _num;
};
int main()
{Student s("tongtong",20);Student s2(s);return 0;
}
对于上面这种写了拷贝构造但不做处理,编译器不会调用父类的拷贝构造。只进行了一次构造,还是因为传参的时候调用。
初始化父类,就传父类的拷贝构造
class Student : public Person
{
public:Student(const Student& s)//直接将子类切片。调用父类的拷贝构造:Person(s),_num(s._num){}
protected:int _num;
};
3、赋值 重载
Student& operator =(const Student& s){if (this != &s){Person::operator =(s);_num = s._num;}return *this;}
4、析构函数
//析构函数会被处理为Destructor,构成隐藏所以用作用域~Student(){Person::~Person();}
int main()
{Student s1("tongtong", 20);
}
如果这样我们的析构会调用三回,本来只需要调用两回,多调用了一会的原因是
Person::~Person();
这个多调用了一会。
析构函数不需要我们自己显示调用,他自己调用父类的析构和子类的析构。
所以为了保证析构的顺序,先析构子再析构父。
如果我们自己操作不能保证这个顺序,
所以编译器帮我们做,子类析构函数完成时,会自动调用父类析构函数,保证先析构子再析构父。
因为要保证顺序,
构造的顺序肯定是先构造父类在构造子类。
四个子类的默认函数调用,除了析构函数,顺序都是先父后子。
5、继承和友元
友元关系不能继承。
下面代码有错误,因为友元函数不能继承,所以我们再有友元函数中不能访问子类的成员,没有继承了父类的友元。
class Student;
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name; // 姓名
};
class Student : public Person
{
protected:int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{cout << p._name << endl;//错误的代码下一句,不可访问cout << s._stuNum << endl;
}
void main()
{Person p;Student s;Display(p, s);
}
但是如果想要访问,就在子类加上友元函数的声明就可以了
class Student;
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name; // 姓名
};
class Student : public Person
{//加上友元就可以使用了。friend void Display(const Person& p, const Student& s);
protected:int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl;
}
void main()
{Person p;Student s;Display(p, s);
}
6、继承与静态成员
父类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例
.7、复杂的菱形继承及菱形虚拟继承
一、单继承
一个子类只有一个直接父类时称这个继承关系为单继承
二、多继承
一个子类有两个或以上直接父类时称这个继承关系为多继承
三、多继承会引起菱形继承
菱形继承是多继承的一种特殊情况。
菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。
使用虚继承解决数据冗余和二义性
8、虚继承继承
现在有一个菱形继承(A B C D)
class A
{
public:int _a;
};class B : public A
{
public:int _b;
};
class C : public A
{
public:int _c;
};
class D : public B, public C
{
public:int _d;
};
在主函数中测试,不能再监视窗口观察,它已经经过处理,我们要在内存窗口观察。
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}
上面没有虚继承,就是单纯的多继承,会有数据冗余和二义性,先观察一下
使用虚继承
内存窗口
将公共继承的A放到一块空间,
B通过第一个地址找到偏移量20,向下走5个地址,从而找到A,就可以改变A。
C通过第一个地址找到偏移量12,向下走3个地址,从而找到A,就可以改变A。
这样就只有一块A,解决数据冗余和二义性
9、继承和组合
public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
相关文章:

C++中的继承
面向对象的三大特性 封装继承多态 继承的概念和定义 继承的本质就是类层次的复用。 继承的概念继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段.它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类…...

SpringRetry接口异常优雅重试机制
场景: 某些场景下,如果接口出现异常需要进行重试,例如网络抖动、调用接口超时等并非接口代码导致的报错,此时可以进行接口重试机制 1、导入 spring retry 重试依赖 <!-- spring retry --><dependency><groupId>…...
2023年全国最新高校辅导员精选真题及答案46
百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 27.充沛的精力和顽强的毅力是教师意志品质的体现。 答案:正确 28.规范与约束…...

程序员为了女朋you进了华为,同学去了阿里,2年后对比收入懵了
什么样的工作才是好工作?每当遇到这个问题,我们的答案总是出奇的一致:钱多事少离家近。 然而现实总是残酷的,日前,有网友在某社交论坛发帖称:自己为了女朋友留在了成都进入华为工作,而自己的同…...

Linux中的算法分离手段
0. 简介 参数分离对于绝大多数算法开发来说收益是非常大的,因为我们都知道,随着平台的更替,很多时候如果说数据流和算法交叠在一起(即接口与实现合在一起)。这将有可能会导致在迁移平台时候会导致代码难以维护&#x…...

机器学习实战:Python基于Logistic逻辑回归进行分类预测
目录1 前言1.1 Logistic回归的介绍1.2 Logistic回归的应用2 iris数据集数据处理2.1 导入函数2.2 导入数据2.3 简单数据查看3 可视化3.1 条形图/散点图3.2 箱线图3.3 三维散点图4 建模预测4.1 二分类预测4.2 多分类预测5 讨论1 前言 1.1 Logistic回归的介绍 逻辑回归ÿ…...

Leetcode.404 左叶子之和
题目链接 Leetcode.404 左叶子之和 easy 题目描述 给定二叉树的根节点 root,返回所有 左叶子 之和。 示例 1: 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以…...

Android 11.0 原生SystemUI下拉通知栏UI背景设置为圆角背景的定制(二)
1.前言 在11.0的系统rom定制化开发中,在原生系统SystemUI下拉状态栏的下拉通知栏的背景默认是白色四角的背景, 由于在产品设计中,在对下拉通知栏通知的背景需要把四角背景默认改成圆角背景,所以就需要分析系统原生下拉通知栏的每条通知的默认背景, 然后通过systemui的通知…...

C语言CRC-16 IBM格式校验函数
C语言CRC-16 IBM格式校验函数 CRC-16校验产生2个字节长度的数据校验码,通过计算得到的校验码和获得的校验码比较,用于验证获得的数据的正确性。基本的CRC-16校验算法实现,参考: C语言标准CRC-16校验函数。 不同厂家通过对输入数…...

Maven高级-聚合和继承
Maven高级-聚合和继承3,聚合和继承3.1 聚合步骤1:创建一个空的maven项目步骤2:将项目的打包方式改为pom步骤3:pom.xml添加所要管理的项目步骤4:使用聚合统一管理项目3.2 继承步骤1:创建一个空的Maven项目并将其打包方式设置为pom步骤2:在子项目中设置其父工程步骤3:…...

如何写出10万+ Facebook 贴文?
想要创作一篇优秀的Facebook贴文,首先要考虑以下几个问题: 1.文案特点 一篇清晰简洁的文案有助于受众在有限的浏览时间内快速了解你想要展示的信息。根据以往经验,文案内容最好保持在20个汉字以内,加上链接描述最好也不要超过50…...

图像处理数据集
BSDS500 Berkeley Segmentation Dataset 500 是第一个用于评估超像素算法的数据集。对于参数优化,使用了验证集。 500张数据集200训练集train100验证集val200测试集test 每张图像有 5 个不同的高质量地面真值分割(groundTruth,是.mat文件) …...

文本聚类与摘要,让AI帮你做个总结
你好,我是徐文浩。 上一讲里,我们用上了最新的ChatGPT的API,注册好了HuggingFace的账号,也把我们的聊天机器人部署了出去。希望通过这个过程,你对实际的应用开发过程已经有了充足的体验。那么这一讲里,我们…...

leaflet实现波动的marker效果(131)
第131个 点击查看专栏目录 本示例的目的是介绍如何在vue+leaflet中显示波动的marker效果。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共76行)安装插件相关API参考:专栏目标示例效果 配置方式 1)查看基础设置…...
关于Dataset和DataLoader的概念
关于Dataset和DataLoader的概念 在机器学习中,Dataset和DataLoader是两个很重要的概念,它们通常用于训练和测试模型时的数据处理。 Dataset是指用于存储和管理数据的类。在深度学习中,通常将数据存储在Dataset中,并使用Dataset提…...
前端与JS变量
前端开发是当今互联网发展的重要组成部分,而JavaScript变量则是前端开发中不可或缺的一部分。在前端开发中,变量的作用不仅仅是存储数据,还可以用来控制程序流程、实现动态效果等。因此,学习前端与JavaScript变量是非常必要的。 …...

初始SpringBoot
初始SpringBoot1. SpringBoot创建和运行1.1. SpringBoot的概念1.2. SpringBoot的优点1.3. SpringBoot的创建1.3.0. 前置工作:安装插件(这是社区版需要做的工作, 专业版可以忽略)1.3.1. 社区版创建方式1.3.2. 专业版创建方式1.3.3. 网页版创建方式1.4. 项目目录介绍1.5. SpringB…...

vue+springboot 上传文件、图片、视频,回显到前端。
效果图 预览: 视频: 设计逻辑 数据库表 前端vue html <div class"right-pannel"><div class"data-box"><!--上传的作业--><div style"display: block" id""><div class"tit…...
java入门-W3(K81-K143)
一. 什么是对象 什么是对象?之前我们讲过,对象就是计算机中的虚拟物体。例如 System.out,System.in 等等。然而,要开发自己的应用程序,只有这些现成的对象还远远不够。需要我们自己来创建新的对象。 例如,…...
English Learning - L2 语音作业打卡 复习元音 [ɜː] [æ] 辅元连读技巧 Day42 2023.4.3 周一
English Learning - L2 语音作业打卡 复习元音 [ɜː] [] 辅元连读技巧 Day42 2023.4.3 周一💌发音小贴士:💌当日目标音发音规则/技巧:中元音 [ɜː]前元音 []辅元连读技巧🍭 Part 1【热身练习】🍭 Part2【练习内容】&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...