【c++】类和对象7—继承
文章目录
- 关于继承
- 继承与非继承的对比
- 继承方式
- 继承中的对象模型
- 继承中的构造和析构顺序
- 继承同名成员处理方式
- 继承同名静态成员处理方式
- 多继承语法
- 菱形继承
关于继承
我们发现,定义一些类时,下级别的成员处理拥有上一级的共性,还有自己的特性。
这时候我们就可以考虑利用继承的技术,减少重复代码。
继承的好处:减少重复代码
语法:
class 子类 : 继承方法 父类;
如:class A:public B;
A类称为子类或派生类
B类称为父类或基类
派生类中的成员包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过来的表现其共性,而新增的成员体现了其个性。
继承与非继承的对比
非继承方式实现:
#include<iostream>
using namespace std;//Java页面
class Java
{
public:void header(){cout << "首页、公开课、登录...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、Python、C++...(公共分类列表)" << endl;}void content(){cout << "Java学科视频" << endl;}
};//Python页面
class Python
{
public:void header(){cout << "首页、公开课、登录...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、Python、C++...(公共分类列表)" << endl;}void content(){cout << "Python学科视频" << endl;}
};//C++页面
class Cpp
{
public:void header(){cout << "首页、公开课、登录...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、Python、C++...(公共分类列表)" << endl;}void content(){cout << "C++学科视频" << endl;}
};void test()
{//Java页面cout << "Java下载视频页面如下:" << endl;Java ja;ja.header();ja.footer();ja.left();ja.content();cout << "-----------" << endl;//Python页面cout << "Python下载视频页面如下:" << endl;Python py;py.header();py.footer();py.left();py.content();cout << "-----------" << endl;//C++页面cout << "C++下载视频页面如下:" << endl;Cpp cp;cp.header();cp.footer();cp.left();cp.content();
}int main()
{test();system("pause");return 0;
}
继承方式实现:
#include<iostream>
using namespace std;//公共页面
class BasePage
{
public:void header(){cout << "首页、公开课、登录...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、Python、C++...(公共分类列表)" << endl;}
};//Java页面
class Java :public BasePage
{
public:void content(){cout << "Java学科视频" << endl;}
};//Python页面
class Python :public BasePage
{
public:void content(){cout << "Python学科视频" << endl;}
};//C++页面
class Cpp :public BasePage
{
public:void content(){cout << "C++学科视频" << endl;}
};void test()
{//Java页面cout << "Java下载视频页面如下:" << endl;Java ja;ja.header();ja.footer();ja.left();ja.content();cout << "-----------" << endl;//Python页面cout << "Python下载视频页面如下:" << endl;Python py;py.header();py.footer();py.left();py.content();cout << "-----------" << endl;//C++页面cout << "C++下载视频页面如下:" << endl;Cpp cp;cp.header();cp.footer();cp.left();cp.content();
}int main()
{test();system("pause");return 0;
}
继承方式
继承的语法:class 子类 : 继承方式 父类
C++中的继承方式有:
public、private、protected三种
(它们直接影响到派生类的成员、及其对象对基类成员访问的规则)
(1)public(公有继承):
继承时保持基类中各成员属性不变,并且基类中private成员被隐藏。
派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;
派生类的对象只能访问基类中的public成员。
(2)protected(保护性继承):
继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。
派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;
派生类的对象不能访问基类中的任何的成员。
(3)private(私有继承):
继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。
派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;
派生类的对象不能访问基类中的任何的成员。
#include<iostream>
using namespace std;class dad
{
public:int m_A;
protected:int m_B;
private:int m_C;
};class son1 :public dad
{
public:void func(){m_A = 10;//父类中的公共权限成员到子类中 依然是公共权限m_B = 20;//父类中的保护权限成员到子类中 依然是保护权限//m_C = 30;//父类中的私有权限成员到子类中 访问不到}
};void test01()
{son1 s1;s1.m_A = 10;//s1.m_B = 20;//son1中m_B是保护权限 类外访问不到
}class son2 :protected dad
{
public:void func(){m_A = 10;//父类中的公共权限成员到子类中 变为保护权限m_B = 20;//父类中的保护权限成员到子类中 依然是保护权限//m_C = 30;//父类中的私有权限成员到子类中 访问不到}
};void test02()
{son2 s2;//s2.m_A = 10;//son2中m_A变为保护权限 类外访问不到//s2.m_B = 20;//son2中m_B是保护权限 不可访问
}class son3 :private dad
{
public:void func(){m_A = 10;//父类中的公共权限成员到子类中 变为私有权限m_B = 20;//父类中的保护权限成员到子类中 变为私有权限//m_C = 30;//父类中的私有权限成员到子类中 访问不到}
};void test03()
{son3 s3;//s3.m_A = 10;//son3中m_A变为私有权限 类外访问不到//s3.m_B = 20;//son3中m_B是私有权限 类外访问不到
}class grandson3 :public son3
{
public:void func(){//m_A = 10;//到son3中m_A变为私有,即使是儿子也访问不到//m_B = 20;//到son3中m_B变为私有,即使是儿子也访问不到}
};int main()
{test01();test02();test02();system("pause");return 0;
}
继承中的对象模型
#include<iostream>
using namespace std;class dad
{
public:int m_A;
protected:int m_B;
private:int m_C;
};class son :public dad
{
public:int m_D;
};void test01()
{//父类中所有非静态成员属性都会被子类继承下去//父类中私有成员属性是被编译器给隐蔽了,因此是访问不到,但是确实被继承下去了cout << "size of son=" << sizeof(son) << endl;//16
}int main()
{test01();system("pause");return 0;
}输出:
size of son=16
继承中的构造和析构顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数。
#include<iostream>
using namespace std;class dad
{
public:dad(){cout << "dad构造函数" << endl;}~dad() {cout << "dad析构函数" << endl;}
};class son :public dad
{
public:son() {cout << "son构造函数" << endl;}~son(){cout << "son析构函数" << endl;}
};void test01()
{dad d;
}void test02()
{cout << "继承中的构造和析构顺序如下:" << endl;//先构造父类,再构造子类,析构的顺序与构造顺序相反son s;
}int main()
{test01();test02();system("pause");return 0;
}输出:
dad构造函数
dad析构函数
继承中的构造和析构顺序如下:
dad构造函数
son构造函数
son析构函数
dad析构函数
总结:
继承中,先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反。
继承同名成员处理方式
访问子类同名成员,直接访问即可;
访问父类同名成员,需要加作用域。
#include<iostream>
using namespace std;class dad
{
public:dad(){m_A = 100;}void func(){cout << "dad的func()调用" << endl;}void func(int a){cout << "dad的func(int a)调用" << endl;}int m_A;
};class son :public dad
{
public:son(){m_A = 200;}void func(){cout << "son的func()调用" << endl;}int m_A;
};//同名成员属性处理
void test01()
{son s;cout << "son下m_A = " << s.m_A << endl;//如果通过子类对象访问到父类中同名成员,需要加作用域cout << "dad下m_A = " << s.dad::m_A << endl;
}//同名成员函数处理
void test02()
{son s;s.func();//直接调用,调用的是子类中的同名成员s.dad::func();//调用到父类中的同名成员函数//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数//如果想访问到父类中被隐藏的同名成员函数,需要加作用域s.dad::func(100);
}int main()
{test01();test02();system("pause");return 0;
}输出:
son下m_A = 200
dad下m_A = 100
son的func()调用
dad的func()调用
dad的func(int a)调用
总结:
1、子类对象可以直接访问子类中同名成员;
2、子类对象加作用域可以访问到父类同名成员;
3、当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数。
继承同名静态成员处理方式
静态成员特点:
1、所有变量共享同一份数据;
2、编译阶段分配内存;
3、类内声明,类外初始化。
静态成员和非静态成员出现同名,处理方式一致:
访问子类同名成员,直接访问即可;
访问父类同名成员,需要加作用域。
#include<iostream>
using namespace std;class dad
{
public:static void func(){cout << "dad的static void func()调用" << endl;}static void func(int a){cout << "dad的static void func(int a)调用" << endl;}static int m_A;
};
int son::m_A = 100;class son :public dad
{
public:static void func(){cout << "son的static void func()调用" << endl;}static int m_A;
};
int son::m_A = 200;//同名成员属性处理
void test01()
{//通过对象访问cout << "通过对象访问:" << endl;son s;cout << "son下m_A = " << s.m_A << endl;//如果通过子类对象访问到父类中同名成员,需要加作用域cout << "dad下m_A = " << s.dad::m_A << endl;//通过类名访问cout << "通过类名访问:" << endl;cout << "son下m_A = " << son::m_A << endl;//第一个::代表通过类名方式访问 第二个::代表访问父类作用域下cout << "dad下m_A = " << son::dad::m_A << endl;
}//同名成员函数处理
void test02()
{//通过对象访问cout << "通过对象访问:" << endl;son s;s.func();//直接调用,调用的是子类中的同名成员s.dad::func();//调用到父类中的同名成员函数//通过类名访问cout << "通过类名访问:" << endl;son::func();son::dad::func();//如果子类中出现和父类同名的静态成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数//如果想访问到父类中被隐藏的同名成员函数,需要加作用域son::dad::func(100);
}int main()
{test01();test02();system("pause");return 0;
}
总结:
同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象和通过类名)。
多继承语法
c++允许一个类继承多个类
语法:class 子类 : 继承方式 父类1, 继承方式 父类2…
多继承可能会引发父类中有同名成员出现,需要加作用域区分
#include<iostream>
using namespace std;class dad1
{
public:dad1(){m_A = 100;}int m_A;
};class dad2
{
public:dad2(){m_A = 200;}int m_A;
};class son :public dad1, public dad2
{
public:son(){m_C = 300;m_D = 400;}int m_C;int m_D;
};void test01()
{son s;cout << "sizeof son = " << sizeof(s) << endl;//当父类在中出现同名成员,需要加作用域区分cout << "dad1::m_A = " << s.dad1::m_A << endl;cout << "dad2::m_A = " << s.dad2::m_A << endl;
}int main()
{test01();system("pause");return 0;
}
菱形继承
概念:
两个派生类继承同一个基类,又有某个类同时继承这两个派生类。
这种继承称为菱形继承,或者砖石继承。
菱形继承问题:
1、产生二义性;
2、继承两份数据,资源浪费。
利用虚继承(加关键字virtual)可以解决菱形继承问题。
#include<iostream>
using namespace std;class animal
{
public:int m_age;
};//利用虚继承 解决菱形继承的问题
//继承之前 加上关键字virtual变为虚继承
//animal类称为虚基类
class sheep :virtual public animal{};class tuo :virtual public animal{};class sheeptuo :public sheep, public tuo{};void test01()
{sheeptuo st;st.sheep::m_age = 18;st.tuo::m_age = 28;//当菱形继承,两个父类拥有相同数就,需要加上作用域区分cout << "st.sheep::m_age = " << st.sheep::m_age << endl;cout << "st.tuo::m_age = " << st.tuo::m_age << endl;cout << "st.m_age = " << st.m_age << endl;//这份数据我们知道,只有一份就可以,菱形继承导致数据有两份,造成资源浪费
}int main()
{test01();system("pause");return 0;
}
相关文章:

【c++】类和对象7—继承
文章目录关于继承继承与非继承的对比继承方式继承中的对象模型继承中的构造和析构顺序继承同名成员处理方式继承同名静态成员处理方式多继承语法菱形继承关于继承 我们发现,定义一些类时,下级别的成员处理拥有上一级的共性,还有自己的特性。 …...

vue实现预览、下载和打印后端返回的pdf文件流
需求:后端返回pdf文件流,前端能够预览、下载打印。 后端返回的文件流部分截图 需要实现的效果图 前面第1步只是为了展示后台返回数据流,完成功能的时候,不需要调用接口的,只需要利用调用接口的url。 实现步骤&am…...

【Android视频号④ 问题总结】
这节坑比较多~ 差点没把我给整死!!! 环境介绍 首先我调试都是root过的真机,但是生产环境都是没有Root的云机,属于自己改的Rom框架也不是XP或LSP 是技术人员利用Xposed源码改的框架 问题&解决 模块源码更改 这…...

推荐算法—widedeep原理知识总结代码实现
wide&deep原理知识总结代码实现1. Wide&Deep 模型的结构1.1 模型的记忆能力1.2 模型的泛化能力2. Wide&Deep 模型的应用场景3. Wide&Deep 模型的代码实现3.1 tensorflow实现3.2 pytorch实现今天,总结一个在业界有着巨大影响力的推荐模型,…...

PHP面向对象03:命名空间
PHP面向对象03:命名空间一、命名空间基础二、子空间三、命名空间访问1. 非限定名称2. 限定名称3. 完全限定名称四、全局空间五、命名空间应用六、命名空间引入一、命名空间基础 namespace,是指人为的将内存进行分隔,让不同内存区域的同名结构…...

Elasticsearch:使用 pipelines 路由文档到想要的 Elasticsearch 索引中去
路由文件 当应用程序需要向 Elasticsearch 添加文档时,它们首先要知道目标索引是什么。在很多的应用案例中,特别是针对时序数据,我们想把每个月的数据写入到一个特定的索引中。一方面便于管理索引,另外一方面在将来搜索的时候可以…...

前端开发常用的18个JavaScript框架和库
JavaScript 可以说是最流行的编程语言之一,也是Web 开发人员必须学习的 3 种语言之一,JavaScript 几乎可以做任何事情,更可以在包括物联网在内的多个平台和设备上运行。在WebGL库和SVG/Canvas元素的支持下,JavaScript变得惊人的强…...

理解、总结重点知识
一、常见的数据结构 1、数组结构 数组结构: 存储区间连续、内存占用严重、空间复杂度大 优点:随机读取和修改效率高,原因是数组是连续的(随机访问性强,查找速度快)缺点:插入和删除数据效率低&a…...

记一次从文件备份泄露到主机上线
前言 记录下某个测试项目中,通过一个文件备份泄露到主机上线的过程。 文件备份泄露 对于测试的第一项当然是弱口令,bp跑了一通词典,无果。目录又爆破了一通,发现一个web.rar可通,赶紧下载看看,如下图所示…...

8年测开经验面试28K公司后,吐血整理出1000道高频面试题和答案
1、python的数据类型有哪些 答:Python基本数据类型一般分为:数字、字符串、列表、元组、字典、集合这六种基本数据类型。 浮点型、复数类型、布尔型(布尔型就是只有两个值的整型)、这几种数字类型。列表、元组、字符串都是序列。 2、列表和元组的区别 答…...

Linux 基础知识之权限管理
目录一、权限的认识二、用户切换三、文件权限1.三类文件访问者2.文件权限类型3.文件访问权限4.文件权限值表示一、权限的认识 权限是对用户所能进行的操作的限制,如果不对用户作出限制,那么碰到恶意用户,就会损害其他用户的利益。 Linux是多用…...

百度LAC分词
对应数据的链接放这里了 import pandas as pd from util.logger import Log import os from util.data_dir import root_dir from LAC import LAC os_file_name os.path.split(os.path.realpath(__file__))[-1]# 加载LAC模型 lac LAC(mode"lac") # 载入自定义词典 …...

软件测试面试题 —— 整理与解析(1)
😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:🌎【Austin_zhai】🌏 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能…...

深入浅出C++ ——红黑树模拟实现STL中的set与map
文章目录一、红黑树二、用泛型红黑树模拟实现set三、用泛型红黑树模拟实现map一、红黑树 红黑树作为set和map的底层容器,既要实现插入key又要实现插入pair,所以做了稍许的改动,使其成为一颗泛型结构的红黑树,通过不同的实例化参数…...

自动化测试框架设计
大数据时代,多数的web或app产品都会使用第三方或自己开发相应的数据系统,进行用户行为数据或其它信息数据的收集,在这个过程中,埋点是比较重要的一环。 埋点收集的数据一般有以下作用: 驱动决策:ABtest、漏…...

【虚拟仿真】Unity3D中实现鼠标的单击、双击、拖动的不同状态判断
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 这篇文章分享一下虚拟仿真项目中经常碰到鼠标事件控制代码。 …...

【2023】Prometheus-相关知识点(面试点)
目录1.Prometheus1.1.什么是Prometheus1.2.Prometheus的工作流程1.3.Prometheus的组件有哪些1.4.Prometheus有什么特点1.5.Metric的几种类型?分别是什么?1.6.Prometheus的优点和缺点1.7.Prometheus怎么采集数据1.8.Prometheus怎么获取采集对象1.9.Promet…...

英语二-电子邮件邀请短文写作
1. 邮件模板 Dear 邀请人, Hope you have a great day. I am writing this email to invite you to attend 主题. Please kindly find the following information for your reference: Time: 时间 Address: 地点 We hope that nothing will prevent you from coming, as…...

如何快速一次性通过pmp考试?
我们就从三个方向进行了解 1.PMP考试难不难? 2.PMP如何备考? 3.考试过程中需要注意什么? 一,PMP考试难不难? 首先关注的问题是,PMP考试难吗?我想全球55%的通过率和学会这边93.9%的通过率&a…...

1-Linux 保存kernel panic信息到flash
在系统运行过程中,如果内核发生了panic,那么开发人员需要通过内核报错日志来进行定位问题。但是很多时候出现问题的时候没有接调试串口,而报错日志是在内存里面的,重启后就丢失了。所以需要一种方法,可以在系统发生crash时&#x…...

linux基本功系列-top命令实战
文章目录一. top命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示进程信息3.2 显示完整的进程命令3.3 以批处理的形式展示3.4 设置信息更新频次3.5 显示指定进程号的信息3.6 top面板中常用参数3.7 其他用法四. top的相关说明4.1 交互命令介绍4.2 top面板每行信息的含义4.2.…...

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?
第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口? 6.5 拓展&#…...

Springboot依赖注入Bean的三种方式,final+构造器注入Bean
文章目录Springboot依赖注入Bean的方式一、Field 注入/属性注入二、set注入三、构造器注入Springboot依赖注入Bean的方式 一、Field 注入/属性注入 Autowired注解的一大使用场景就是Field Injection。 Controller public class UserController {Autowiredprivate UserServic…...

【java】Spring Cloud --Spring Cloud Alibaba 微服务解决方案
文章目录1、Spring Cloud Alibaba 是什么先说说 Spring CloudSpring Cloud Alibaba和Spring Cloud 的区别和联系Spring Cloud Alibaba2、Spring Cloud Alibaba 包含组件阿里开源组件阿里商业化组件集成 Spring Cloud 组件3、Spring Cloud Alibaba 功能服务注册与发现支持多协议…...

CSS 6种选择器(超详细)
CSS6大种选择器(超详细) 一、常用的css基本选择器(4种) 1、标签选择器 结构: 标签名{css属性名:属性值} 作用:通过标签名,找到页面中所有的这类标签,设置样式 注意:1.标签选择器选择的是一类标签&#…...

mysql8.0.32-手动配置安装-具体流程步骤
文章目录1.下载mysql压缩编译版2.修改配置文件3.数据库初始化,安装windows服务,启动服务4.修改root密码5.作者答疑1.下载mysql压缩编译版 作者从官方下载:https://download.csdn.net/download/m0_67316550/87485720 2.修改配置文件 修改my…...

【项目】Vue3+TS 退出登录 menu header搭建
💭💭 ✨:【项目】Vue3TS 退出登录 menu header搭建 💟:东非不开森的主页 💜: 今天永远比昨天更好💜💜 🌸: 如有错误或不足之处,希望可以指正&#x…...

LoRaWAN模块在车辆跟踪定位中的应用
目前 GPS已经在资产的管理中得到了越来越多的运用,如车辆跟踪、车队跟踪、资产监控等;人员跟踪,宠物跟踪,等等。在所有追踪装置中,最重要的是它的电池期望和监视距离。鉴于 LoRaWAN的功率消耗很小,而且能在…...

软件测试分类
软件测试分类 从上图我们发现软件测试根据不同的分类条件会有不同的结果. 1. 按照阶段进行划分 1.1 单元测试(Unit Testing) 单元测试是对软件组成单元进行测试。其目的是检验软件基本组成单位的正确性。测试的对象是软件设计的最小单位:模块。 测试阶段&#x…...

外置的媒体查询,对性能又一次的优化提升
通常情况下我们写媒体查询都是写在一个样式文件中,对于浏览器加载的时候,会解析到最后一行样式时才会渲染页面,这样就会造成页面的白屏时间过长。 但是通常情况下大量的媒体查询样式都是无用的,现在浏览器允许我们在引用样式文件…...