当前位置: 首页 > news >正文

【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—继承

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

vue实现预览、下载和打印后端返回的pdf文件流

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

【Android视频号④ 问题总结】

这节坑比较多~ 差点没把我给整死&#xff01;&#xff01;&#xff01; 环境介绍 首先我调试都是root过的真机&#xff0c;但是生产环境都是没有Root的云机&#xff0c;属于自己改的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实现今天&#xff0c;总结一个在业界有着巨大影响力的推荐模型&#xff0c…...

PHP面向对象03:命名空间

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

Elasticsearch:使用 pipelines 路由文档到想要的 Elasticsearch 索引中去

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

前端开发常用的18个JavaScript框架和库

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

理解、总结重点知识

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

记一次从文件备份泄露到主机上线

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

8年测开经验面试28K公司后,吐血整理出1000道高频面试题和答案

1、python的数据类型有哪些 答&#xff1a;Python基本数据类型一般分为&#xff1a;数字、字符串、列表、元组、字典、集合这六种基本数据类型。 浮点型、复数类型、布尔型(布尔型就是只有两个值的整型)、这几种数字类型。列表、元组、字符串都是序列。 2、列表和元组的区别 答…...

Linux 基础知识之权限管理

目录一、权限的认识二、用户切换三、文件权限1.三类文件访问者2.文件权限类型3.文件访问权限4.文件权限值表示一、权限的认识 权限是对用户所能进行的操作的限制&#xff0c;如果不对用户作出限制&#xff0c;那么碰到恶意用户&#xff0c;就会损害其他用户的利益。 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)

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;&#x1f30e;【Austin_zhai】&#x1f30f; &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xf…...

深入浅出C++ ——红黑树模拟实现STL中的set与map

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

自动化测试框架设计

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

【虚拟仿真】Unity3D中实现鼠标的单击、双击、拖动的不同状态判断

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

【2023】Prometheus-相关知识点(面试点)

目录1.Prometheus1.1.什么是Prometheus1.2.Prometheus的工作流程1.3.Prometheus的组件有哪些1.4.Prometheus有什么特点1.5.Metric的几种类型&#xff1f;分别是什么&#xff1f;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考试难不难&#xff1f; 2.PMP如何备考&#xff1f; 3.考试过程中需要注意什么&#xff1f; 一&#xff0c;PMP考试难不难&#xff1f; 首先关注的问题是&#xff0c;PMP考试难吗&#xff1f;我想全球55%的通过率和学会这边93.9%的通过率&a…...

1-Linux 保存kernel panic信息到flash

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

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...