【C++ 进阶】继承

news/2024/10/23 9:36:06/

一.继承的定义格式

基类又叫父类,派生类又叫子类;


二.继承方式

继承方式分为三种:

     1.public继承

     2.protected继承

     3.private继承

基类成员与继承方式的关系共有9种,见下表:

 虽然说是有9种,但其实最常用的还是红框里的,其它的很少用。

 总结

1. 基类private成员在派生类中无论以什么方式继承都是不可见的

    不可见指:基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不       管在类里面还是类外面都不能去访问它;

2.如果想要在派生类访问基类中的成员变量,可以在基类中定义为 protected 成员

3.基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式)

4.使用关键字class时默认的继承方式是private

   使用struct时默认的继承方式是public


三.派生类和基类之间的赋值转换

 1.派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用,这个过程又被形象的称为      切片/切割

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

3.基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的;


四.隐藏(重定义)

1.子类和父类中,只要函数名相同就构成隐藏

2.成员名相同也构成隐藏;

3.在子类成员函数中,可以使用 基类::基类成员 显示访问隐藏的函数或成员;

4.最好不要定义同名的成员变量。

隐藏(重定义)与重载

重载:在同一作用域

隐藏:在不同的作用域,一个在父类,一个在子类


五.派生类中的默认成员函数

1.构造函数

   派生类必须先自动调用基类的默认构造(初始化基类的那一部分成员),如果基类没有默     认构造,就要在派生类的初始化列表阶段显式调用基类的构造函数,然后派生类调用自己     的构造函数。

2.拷贝构造

   派生类的拷贝构造必须先调用基类的拷贝构造完成基类的拷贝初始化。

3.赋值重载

   派生类赋值重载必须先调用基类的赋值重载完成基类的复制。

4.析构函数

   销毁对象时,会先调用派生类的析构函数,然后再自动调用基类的析构函数,这样就保证     了析构的顺序(即先子后父)

   如果不是这个顺序,一个成员可能会析构两次,就会导致程序崩溃,比如以下的代码:

class A
{
public:~A(){delete _a;}int* _a = new int;
};class B :public A
{
public:~B(){delete _b;  A::~A();   //显式调用父类的析构函数,在调用完后,编译器又会自动调用一次父类的析构函数, //导致父类成员_a析构了两次,从而程序崩溃}int* _b = new int;
};int main()
{A  a;B b;return 0;
}

六.继承与友元,静态成员

 友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员;

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子
类,都只有一个static成员实例 ,静态成员不属于任何一个具体的实例对象,而是属于类本身,子类可以继承父类的静态成员,而不需要重新定义。


七.多继承

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

下面就是一个多继承:

class A
{};class B
{};class C:public A,public B   //多个父类之间用逗号隔开
{};

多继承的一个坑:菱形继承

 上图就构成了一个菱形继承,它会导致两个问题:

   1.数据冗余,因为会存两个Person类;

   2.二义性

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._a;   //二义性问题,不知道访问的是哪个_a;d.A::_a;   //显式访问,解决了二义性问题,但无法解决数据冗余问题return 0;
}

虚拟继承:解决菱形继承问题

在菱形继承的腰部加上 virtual  关键字构成虚拟继承

如将上面代码class B 和  class C  改成:

class B: virtual public A   //虚拟继承
{};class C: virtual public A
{};

原理

通过观察菱形继承和虚拟继承的内存窗口我们发现:

 

 


八.总结和反思

1.public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象

2.组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象

例如:

class A
{};class B
{A a;   //组合
};

3.组合的耦合性比继承低,所以一般推荐使用组合。


🐬🤖本篇文章到此就结束了, 若有错误或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼


http://www.ppmy.cn/news/979664.html

相关文章

无涯教程-jQuery - stopPropagation()方法函数

stopPropagation()方法停止将事件冒泡到父元素,从而防止任何父处理程序收到该事件的通知。 您可以使用方法 event.isPropagationStopped()来了解是否曾经在该事件对象上调用过此方法。 stopPropagation() - 语法 event.stopPropagation() stopPropagation() - …

网络安全进阶学习第七课——文件包含漏洞

文章目录 一、文件包含概念二、文件包含漏洞原理三、文件包含分类文件包含分为两种: 四、与文件包含相关的配置文件:(php.ini文件)五、与文件包含有关的函数1、include()2、include_once()3、require()4、require_once() 六、文件…

FCPX插件-15组金色华丽粒子特效闪耀动画 Awards Backgrounds

Awards Backgrounds是fcpx上一个很棒的电影级效果插件,Awards Backgrounds 包含15组金色华丽粒子特效闪耀动画,可以为您的作品创建豪华的背景或叠加特效!包含各种带有可编辑颜色的下落闪闪发光粒子的场景。用于展示奖项提名者、优雅的表演、祝…

探索NE555:一款经典的集成电路(超详细)

NE555是一款经典的集成电路,它在电子领域被广泛应用于定时器、脉冲发生器、电压控制振荡器等各种应用场景。它的设计简单、易于使用,并且具备稳定可靠的性能,因此深受电子爱好者和工程师的青睐。本篇博客将详细介绍NE555的原理、工作模式和常…

下拉框可筛选可树状多选组件

实际效果图片 父页面 <el-form-item label"转发&#xff1a;" :label-width"formLabelWidth" class"formflex_item"><el-select ref"select" :clearable"true" clear"clearSelect" remove-tag"r…

android 高版本sd卡目录读写权限

1、从安卓11不允许访问sd目录&#xff0c;官方说明如下&#xff1a; https://developer.android.com/about/versions/11/privacy/storage?hlzh-cn 2、使用MediaStore方法 一手遮天 Android - 存储: Android 11 通过 MediaStore 管理文件 - webabcd - 博客园 (cnblogs.com) …

开发一个RISC-V上的操作系统(三)—— 串口驱动程序(UART)

目录 文章传送门 一、什么是串口 二、本项目串口的FPGA实现 三、串口驱动程序的编写 四、上板测试 文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&…

小学期笔记——天天酷跑3

画笔的载体是图层 图层的载体是窗体 效果&#xff1a; ------------------- 效果&#xff1a; ---------------------- 实现一个接口可以理解成添加一个能力 接口可以理解为能力的集合 对于abstract&#xff08;判断&#xff1a;没有方法体&#xff09;&#xff0c;尽量使用…