【C++ | 继承】C++的继承详解 及 例子源码演示

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、继承的定义
  • 🎄三、派生类(子类)继承了什么
    • ✨3.1 派生类从基类继承了哪些东西
    • ✨3.2 继承的东西怎么使用
  • 🎄四、派生类对象的创建、销毁
  • 🎄五、
  • 🎄六、



在这里插入图片描述

🎄一、概述

继承的概念:

  • 继承(inheritance)机制是面向对象程序设计中使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。
  • 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用

通过继承可以完成的一些工作:

  • 1、可以在己有类的基础上添加功能。 例如, 对于数组类, 可以添加数学运算。
  • 2、可以给类添加数据。 例如, 对于字符串类, 可以派生出一个类, 并添加指定字符串显示颜色的数据成员。
  • 3、可以修改类方法的行为。

按照继承权限区分,有公开继承、保护继承、私有继承三种方式。
按照继承的直接基类个数区分,有单继承、多重继承两种方式。


在这里插入图片描述

🎄二、继承的定义

通过继承 ( inheritance ) 联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类(base class),其他类则直接或间接地从基类继承而来,这些继承得到的类称为派生类(derived class)。基类负责定义在层次关系中所有类共同拥有的成员, 而每个派生类定义各自特有的成员

派生类必须通过使用**类派生列表(class derivation list)**明确指出它是从哪个(哪些)基类继承而来的。
类派生列表的形式是:首先是一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面可以有访问说明符。
在这里插入图片描述
访问说明符有三种:pulbic(公有继承)、protect(保护继承)、private(私有继承)。
类派生列表也可以有多个基类,如:class CDog : public CAnimal, public CFriend

下面用代码演示一下继承的过程:

class CAnimal{
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[64];
};class CDog : public CAnimal{};

is-a:我们这里使用的是 公有继承,它需要遵循is-a的关系,就是派生类 is a 基类,可以表示成派生类 是 基类,例如“狗 是 动物”。按照这个关系,我们不能在 动物苹果 之间使用公有继承。派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行。


在这里插入图片描述

🎄三、派生类(子类)继承了什么

继承完之后,那么派生类继承了哪些东西?这些东西怎样使用呢?这个小节,我们来学习这两个问题的答案。

✨3.1 派生类从基类继承了哪些东西

派生类继承了基类的 数据成员 和 大部分的函数成员,而基类的 构造函数、析构函数、赋值运算符函数 不会被派生类所继承。

下面修改一下上面的代码,演示派生类继承了父类的数据成员。

// 22_Inheritance.cpp
// g++ 22_Inheritance.cpp 
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
private:int m_hairColor;	// 毛发颜色
};int main ()
{CAnimal animal;cout << "sizeof(animal)=" << sizeof(animal) << endl;CDog dog;cout << "sizeof(dog)=" << sizeof(dog) << endl;return 0;
}

运行结果如下:

从结果来看,派生类CDog 比基类CAnimal 多了 4 个字节。这4个字节刚好是一个int型,也就是派生类多的 m_hairColor 成员。而成员函数也是被继承的,但成员函数并不会放在类对象的内存中,而是放在程序的代码段。打印类对象大小只会打印该对象的数据成员总和。

在这里插入图片描述

✨3.2 继承的东西怎么使用

派生类继承的成员并不是可以随意地访问,跟继承时使用的 访问说明符 以及该成员在 基类中的访问权限 有关。

按照访问说明符的不同,可以分为public继承、protected继承、private继承,它们从基类继承到的成员访问权限如下表:

类成员\继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员
基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见

从表格可以得出下面几个结论:
1、基类的私有成员,在派生类无法访问,只能通过基类的公有成员函数去访问。
2、基类的公有成员、保护成员,可以在派生类成员函数直接访问。
3、公有继承中,基类的公有成员、保护成员在派生类中也分别是公有、保护。
4、保护继承中,基类的公有成员、保护成员在派生类中都是保护的。
5、私有继承中,基类的公有成员、保护成员在派生类中都是私有的。

综上所述,派生类继承到的东西,并不是可以随意使用,而是按照上面表格和结论去使用。下面用代码演示怎样使用。代码使用了公有继承,基类的公有成员将成为派生类的公有成员;基类的私有部分也将成为派生类的一部分,但只能通过基类的公有和保护方法访问。

// 22_Inheritance1.cpp
// g++ 22_Inheritance1.cpp 
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}void SetName(const char *name)// 修改私有成员 m_name{int len = strlen(name) > NAME_LEN ? NAME_LEN : strlen(name);memset(m_name, 0, sizeof(m_name));strncpy(m_name, name, len);}const char *GetName(){return m_name;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
public:enum{HAIR_BLACK, HAIR_WHITE};CDog(){m_hairColor = HAIR_BLACK;//sprintf(m_name, "Dog"); // 报错,基类私有成员在派生类无法访问。}
private:int m_hairColor;	// 毛发颜色
};int main ()
{CAnimal animal;animal.run();CDog dog;dog.run();CDog dog1;dog1.SetName("dog1");dog1.run();return 0;
}

运行结果如下,代码演示了公有继承,派生类无法访问基类的m_name,但可以通过基类的公有函数SetName去修改m_name:
在这里插入图片描述


在这里插入图片描述

🎄四、派生类对象的创建、销毁

我们定义了一个派生类,大概率是需要用到这个派生类的对象的,那么派生类对象是怎样创建、销毁的呢?

创建派生类对象的几个要点:
1、派生类没有继承基类的构造函数。
2、创建派生类对象时,程序会先创建派生类对象的基类部分,所以,会先调用基类的构造函数,再调用派生类构造函数。
3、如果没有显式地调用基类构造函数,那么程序会自动调用基类的 无参构造函数 来创建派生类对象的基类部分。
4、如果要显式调用基类构造函数,为了保证先创建基类部分,需要在派生类构造函数的 成员初始化列表 去调用。
5、一般情况下,让基类构造函数初始化基类部分,派生类构造函数初始化派生类新增的数据成员。

派生类对象的销毁
派生类对象的销毁时,会先调用派生类的析构函数,再调用基类的析构函数。这个顺序与创建时相反。

🌰举例子:

// 22_Inheritance2.cpp
// g++ 22_Inheritance2.cpp 
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal()						// 无参构造{sprintf(m_name, "Ainmal");cout << "Calling CAnimal(): this=" << this << endl;}CAnimal(char *name){int len = strlen(name) > NAME_LEN ? NAME_LEN : strlen(name);memset(m_name, 0, sizeof(m_name));strncpy(m_name, name, len);cout << "Calling CAnimal(char*): this=" << this << endl;}~CAnimal()						// 无参构造{cout << "Calling ~CAnimal(): this=" << this << endl;}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
public:enum{HAIR_BLACK, HAIR_WHITE};CDog(){cout << "Calling CDog(): this=" << this << endl;m_hairColor = HAIR_BLACK;}CDog(int color, char* name) : CAnimal(name){cout << "Calling CDog(int, char*): this=" << this << endl;m_hairColor = color;}~CDog(){cout << "Calling ~CDog(): this=" << this << endl;}
private:int m_hairColor;	// 毛发颜色
};int main ()
{CDog dog;dog.run();cout << endl;CDog dog1(CDog::HAIR_BLACK, (char*)"dog1");dog1.run();cout << endl;return 0;
}

运行结果:
在这里插入图片描述


在这里插入图片描述

🎄五、

在这里插入图片描述

🎄六、

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

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

相关文章

信用卡没逾期就万事大吉了吗?

6月28日&#xff0c;中国人民银行揭晓了《2024年第一季度支付体系概览》&#xff0c;数据显示&#xff0c;截至本季度末&#xff0c;信用卡及借贷合一卡的总量为7.6亿张&#xff0c;与上一季度相比&#xff0c;这一数字微降了0.85个百分点。同时&#xff0c;报告还指出&#xf…

AE的合成

目录 合成的概念 合成设置 预设 像素长宽比 分辨率​编辑 开始时间码和持续时间 背景颜色 合成的实战理解 在AE的操作界面中&#xff0c;当我们新建了一个项目之后&#xff0c;画面中最主要的位置显示的是新建合成 合成的概念 AE是一款专业特效合成软件&#xff0c;可…

【吊打面试官系列-MyBatis面试题】MyBatis 实现一对一有几种方式?具体怎么操作的?

大家好&#xff0c;我是锋哥。今天分享关于 【MyBatis 实现一对一有几种方式?具体怎么操作的&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MyBatis 实现一对一有几种方式?具体怎么操作的&#xff1f; 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询…

Golang 指针+运算符

指针 获取变量的地址(指针)&#xff0c;用 & 操作符&#xff0c;比如 &number 指针类型&#xff0c;存储的是一个地址&#xff0c;比如 *int&#xff0c;*float64 访问指针类型指向空间&#xff0c;用 *&#xff0c;比如 *ptr 指针空值类型是nil &#xff0c;而不是…

【记录】如何使用IDEA2023

前言&#xff1a; 记录IDEA2023的激活与安装 第一步&#xff1a;官网下载安装包&#xff1a; 下载地址&#xff1a;https://www.jetbrains.com/idea/download/other.html 这个最好选择2023版本&#xff0c;用着很nice。 安装步骤就不详解了&#xff0c;无脑下一步就可以了…

【并发编程】-3.锁的类型、CAS、UNSAFE、原子操作

锁的类型 可重入锁和不可重入锁 可重入锁&#xff1a;一个线程可以多次抢占同一个锁&#xff1b;Synchronized、ReentrantLock都是可重入锁&#xff0c;用Synchronized进行锁的可重入测试&#xff0c;在同一个线程中定义childMethod()和childMethod2()两个方法&#xff0c;在这…

RabbitMQ实现延迟消息

前提条件 确保RabbitMQ已安装并启用了RabbitMQ Delayed Message插件。如果尚未启用&#xff0c;可以按照以下步骤操作&#xff1a; 下载插件&#xff1a; 从RabbitMQ社区插件页面下载rabbitmq_delayed_message_exchange插件。 安装插件&#xff1a; 将插件文件&#xff08;.e…

使用Github Actions自建Docker镜像仓库

使用Github Actions自建Docker镜像仓库 背景使用Github Actions自建Docker镜像仓库fork项目[docker_image_sync](https://github.com/xqxyxchy/docker_image_sync)获取云厂商容器镜像服务信息配置github secrets运行github action配置需要同步的镜像同步后效果华为云配置 背景 …

Casbin简单介绍、使用场景以及使用步骤

概述&#xff1a; Casbin是一个强大的、高效的开源访问控制框架&#xff0c;其权限管理机制支持多种访问控制模型&#xff0c;包括ACL&#xff08;访问控制列表&#xff09;、RBAC&#xff08;基于角色的访问控制&#xff09;和ABAC&#xff08;基于属性的访问控制&#xff09…

VCS+Vivado联合仿真BUG

场景&#xff1a; 在vcsvivado联合仿真过程中&#xff0c;对vivado导出的shell脚本修改&#xff0c;修改某些source文件路径&#xff0c;vcs编译时会报Permission Denied。 问题描述 对shell脚本修改如下&#xff1a; 修改仅为注释掉某一行&#xff0c;下面变为source文件新…

昇思25天学习打卡营第07天|函数式自动微分

神经网络的训练主要使用反向传播算法&#xff0c;模型预测值&#xff08;logits&#xff09;与正确标签&#xff08;label&#xff09;送入损失函数&#xff08;loss function&#xff09;获得loss&#xff0c;然后进行反向传播计算&#xff0c;求得梯度&#xff08;gradients&…

Laravel批量插入:提升数据库性能的秘诀

标题&#xff1a;Laravel批量插入&#xff1a;提升数据库性能的秘诀 在Web应用开发中&#xff0c;尤其是使用Laravel框架时&#xff0c;经常需要将大量数据插入数据库。Laravel的批量插入功能可以显著提高插入效率&#xff0c;减少对数据库的请求次数&#xff0c;从而提升应用…

Kubernetes RBAC 之 ServiceAccount

Kubernetes RBAC 之 ServiceAccount 定义 RABC 英文全称是 Role-Based Access Control&#xff0c;它通过角色绑定账户&#xff0c;来使得账户拥有某些操控 K8S 集群的权限。ServiceAccount 是集群内部 Pod 访问集群所使用的服务账户&#xff0c;它包括了 Namespace、Token、…

hid-ft260驱动学习笔记 1 - 驱动模块注册与注销

目录 1. ft260_driver_init初始化 1.1 tty设备 1.1.1 申请tty驱动设备 1.1.2 初始化tty驱动程序 1.1.3 注册tty设备 1.2 hid设备 2. ft260_driver_exit注销模块 3. 调试 hid-ft260.c的最底部可以看到该驱动的注册与注销接口的申明。 module_init(ft260_driver_init); …

C++:申明Declaration与定义Definition的本质与区别

在C中&#xff0c;声明和定义是两个不同的概念。 声明&#xff08;Declaration&#xff09; 声明是告诉编译器关于变量、函数等的存在以及它们的类型&#xff0c;但并不提供实际的存储空间或函数体。例如&#xff0c;你可以在程序的不同位置声明一个函数或者类&#xff0c;以…

eclipse ide中文件编码的修改,解决中文乱码的问题。

1、先上一张图&#xff1a; 记得之前设置过&#xff0c;但是稍微一变&#xff0c;环境编码又到了ISO-8859-1了&#xff0c;然后就出现了乱码。 2、设置eclipse的编码&#xff1a; Preferences--General -- Content Types -- Text -- Java Properties File -- Default encoding…

使用myCobot280和OAK-D OpenCV DepthAI摄像头制作一个实时脸部跟踪的手机支架!

引言 由于YouTube和Netflix的出现&#xff0c;我们开始躺着看手机。然而&#xff0c;长时间用手拿着手机会让人感到疲劳。这次我们制作了一个可以在你眼前保持适当距离并调整位置的自动移动手机支架&#xff0c;让你无需用手拿着手机。请务必试试&#xff01; 准备工作 这次我们…

名企面试必问30题(二十)——你对薪资的要求?

1.思路 1. 表明您对薪资的看法是基于自身能力、市场行情和公司薪酬体系的综合考量。 2. 强调您希望薪资能够合理反映您的专业技能、经验和对公司可能做出的贡献。 3. 提及您已经对市场和公司薪酬情况做了一定了解&#xff0c;给出一个大致合理的范围。 2.参考解答 话术示例…

Python内置函数print()详解

在Python编程中&#xff0c;print()函数是最常用的内置函数之一&#xff0c;用于将信息输出到标准输出设备&#xff0c;通常是屏幕。这个函数非常灵活&#xff0c;可以输出各种类型的数据&#xff0c;并且支持多种参数来定制输出格式。 函数功能 print()函数的主要功能是输出…

Vue3从入门到精通(三)

vue3插槽Slots 在 Vue3 中&#xff0c;插槽&#xff08;Slots&#xff09;的使用方式与 Vue2 中基本相同&#xff0c;但有一些细微的差异。以下是在 Vue3 中使用插槽的示例&#xff1a; // ChildComponent.vue <template><div><h2>Child Component</h2&…