继承(下)【C++】

文章目录

接上"集"【继承 (上)【C++】

子类继承父类之后,子类的默认成员函数的变化

构造函数

编译器自动生成的构造函数

子类中的编译器自动生成的构造函数,会先子类构造函数的成员初始化列表中调用父类的默认构造函数【即不需要传参数,就能调用的构造】,再完成子类自己的构造函数



如果父类没有默认构造,编译器自动生成的构造函数就会报错

此时需要我们手动写子类的构造函数,并在其成员初始化列表传参调用父类的构造


程序员手动写的构造函数

子类中,程序员手动写的构造函数,在我们自己没有在成员初始化列表中显式调用父类的构造的时候,编译器也会帮我们自动调用父类的默认构造



当然此时如果父类没有默认构造,就必须我们自己手动在成员初始化列表里传参调用了




拷贝构造

编译器自动生成的拷贝构造函数

子类中,编译器自动生成的拷贝构造函数,会先自动在子类的拷贝构造的成员初始化列表中调用父类的拷贝构造,再完成子类自己的拷贝构造


程序员手动写的拷贝构造函数

因为手动写了,所以编译器不会自动生成拷贝构造了,那么编译器就不会自动帮我们调用父类的拷贝构造了

所以

子类中,程序员手动写的拷贝构造函数必须由程序员自己手动在子类的拷贝构造的成员初始化列表中,传参调用父类的拷贝构造【此时传参,传子类的拷贝构造接收到的参数就行,因为继承(上)中提到的子类对象可以赋值给父类对象子类对象多出来的部分会"切割"掉



赋值重载

编译器自动生成的赋值重载

子类中,编译器自动生成的赋值重载函数,会先自动地调用父类的赋值重载,再完成子类自己的赋值重载



程序员手动写的赋值重载

因为手动写了,所以编译器不会自动生成赋值重载了,那么编译器就不会自动帮我们调用父类的赋值重载了


所以

子类中,程序员手动写的赋值重载必须由程序员自己手动在子类的赋值重载中

传参调用父类的赋值重载【此时传参,传子类的拷贝构造接收到的参数就行,因为继承(上)中提到的子类对象可以赋值给父类对象子类对象多出来的部分会"切割"掉


为什么在子类中调用父类的赋值重载必须要指定父类的类域呢?

这是因为,子类和父类的赋值重载同名了构成了隐藏继承 (上)【C++】中就说过:

如果在子类里面调用构成隐藏的成员,不指定类域的话,就只会调用子类自己的成员

所以才必须指定父类的类域,这样才能调用到父类的赋值重载


析构函数

析构函数比较特殊,无论是编译器自动生成的析构还是程序员自己手动写的析构

子类的析构调用完成之后,都会再自动地调用父类析构




继承与友元

类和对象【六】友元和内部类中就提到过
友元关系是不能继承的,也就是说父类友元不能访问子类私有和保护成员

可以形象的理解成妈妈的朋友不是我的朋友

但是也不是说我不能和她交朋友


菱形继承

什么是菱形继承?

举个例子

这样继承的话,D里面就会有两份A的成员,就会造成两个重大的问题:

  1. 数据冗余:即D类里面有两份A的成员,而且这两份完全重复,没有必要都存在
  2. 访问会有二义性:因为D类里面有两份A的成员,那么通过D类的对象访问A类的成员就不知道要访问这两份中的那一份

如何解决菱形继承?

使用虚继承可以解决菱形继承产生的问题【注意:不要在解决菱形继承以外的场景中使用虚继承】

使用虚继承之后,D类中就只有一份A的成员了

虚继承的语法:
在会产生两份(多份)数据的根源的继承权限的前面加上virtual

上面那个例子就是在B和C继承A的时候,在B和C的继承权限前面加上关键字virtual即可

因为B和C继承A时,就是D中会产生两份A的数据的根源


虚继承的原理

继续使用之前的例子

①使用虚继承之前:

D类对象的组成如上图

D类里面,有两个父类的部分,一个从B那里继承来的(以下简称D中的B),一个从C那里继承来的(以下简称D中的C)

他们里面都有类A的成员(即a)

②使用虚继承之后:

D类对象的组成如下图

也就是使用虚继承之后:

B类和C类的父类A的成员,会单独存在D类对象的最后,然后D类中的B和C就共享这公共的A

这个时候,D中的B和C原本存储A类的成员的地方就变成存储一个指针(称为虚基表指针)

这个指针指向一张虚基表,虚基表里面存了偏移量

D对象中的B和C就可以通过各自的虚基表指针,找到各自的虚拟表
然后通过里面存储的偏移量找到D对象中存储的公共的A的成员


菱形继承的使用建议【能不用就不用】

现实编写代码的过程中,可以使用多继承,但是尽量不要产生菱形继承


菱形继承能不用就不用


相关推荐
唐诺1 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨2 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客2 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin2 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos4 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室4 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0015 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我585 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc5 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很5 小时前
C++ 集合 list 使用
c++