一.概述
1.介绍
继承:是面向对象编程(OOP)的四大特性之一,它允许我们根据一个已有的类来定义一个新的类,称为派生类(或子类),这个已有的类称为基类(或父类)。派生类会继承基类的属性和方法。
继承的作用:实现代码的重用,提高软件开发效率
2.不能被继承的东西
- 父类的构造函数
- 析构函数
- 虽然不能继承,但子类可以调用(虚析构)
- operator=,重载的等号
- 这些是父类专用的,子类继承过去反而会导致异常
二.继承的定义
1.继承的类型
(1)类型
父类中的私有数据子类虽可继承,但不可见,需使用公共方法调用
-
公共继承 public (常用)
公共继承会原样继承父类的内容,不会修改从父类继承过来数据的权限
-
保护继承 protected
保护继承会将从父类继承过来的数据全部设为受保护的
-
私有继承 private
私有继承会将从父类继承过来的数据全部设为私有
(2)不同类型的权限
不同的继承类型,使得从父类继承过来的数据呈现不同的权限
![image-20240315092916921](https://honescos.oss-cn-hangzhou.aliyuncs.com/img/image-20240315092916921ju2XPDJ0bO2024031509297275dbf26ceaf026.png)
代码层面:
![image-20240315092315660](https://honescos.oss-cn-hangzhou.aliyuncs.com/img/image-20240315092315660KkSFWYbUTi202403150923cfcfdf07da3d0bc8.png)
(3)注意事项
-
C++的继承区分继承的方式,不同的方式对应不同的权限
-
无论是什么继承方式,父类中的private数据在子类中虽然继承过去了,但都是不可见的,可以通过父类提供的公共方法获取
2.继承的格式&示例
格式:
class 父类{};
class 子类:继承类型 父类名{
//子类新增数据
};
示例:
class Father{};
class Son:public Father{
};
三.继承中的构造和析构
1.构造&析构的顺序
(1)顺序
创建子类对象的顺序:
- 先构造父类
- 再构造成员
- 最后构造子类自身
析构子类对象的顺序:
这意味着一旦子类的析构被调用,那父类的析构也必将被调用(虚析构涉及)
- 先析构子类自身
- 再析构成员
- 最后析构父类
图例:
![image-20240315160143109](https://honescos.oss-cn-hangzhou.aliyuncs.com/img/image-20240315160143109qUwiNVUyDG202403151601cb01df37316cc014.png)
(2)示例
代码:
#include
using namespace std;
class Base
{
public:
int a;
public:
Base()
{
cout<<"父类默认构造"<
结果:
父类默认构造
Other默认构造
Son默认构造
Son析构
Other析构
父类析构
2.子类调用成员对象、父类的构造
无参构造自动调用、有参构造按规则用参数列表
(1)概述
默认情况下,子类是会自动调用成员对象、父类的默认构造(无参构造) 的,如果需要调用成员对象、父类的有参构造,则使用初始化列表。
(2)格式
⭐ 初始化列表时,父类要写类名称,成员对象要写对象名
类名(值1,值2):成员对象1(值1),父类类名称(值2){
//子类自身属性在此赋值
}
(3)示例
代码:
#include
using namespace std;
class Base
{
public:
int a;
public:
Base()
{
cout<<"父类默认构造"<a = a;
cout<<"父类有参构造"<b = b;
cout<<"Other有参构造"<c = c;
cout<<"Son有参构造"<
结果:
父类有参构造
Other有参构造
Son有参构造
Son析够
Other析够
父类析够
四.子父类重名成员
1.概述
当子类中成员和父类中成员重名时,默认访问的是子类中的重名成员, 而父类中的相关成员将会被屏蔽,如果想要访问父类中的重名成员,可以通过加作用域 /ins>的形式进行访问。
2.访问重名对象
存在重名对象的时候,默认访问的是子类的对象
(1)格式
使用子类调用父类的成员的时候,成员名的前面添加作用域指向父类即可
子类对象.父类名::重名成员名
(2)实现
代码:
#include
using namespace std;
class Father {
public:
int num;
public:
Father(){}
Father(int num){
this -> num = num;
}
};
class Son:public Father{
public:
int num;
public:
Son(){}
Son(int x,int y):Father(y)
{
num = x;
}
};
int main(){
Son son = Son(10, 20);
//存在重名对象的时候,默认访问的是子类的对象
cout << "访问子类重名成员:"<< son.num <
返回值:
访问子类重名成员:10
访问父类重名成员:20
3.访问重名函数
(1)重名函数-函数重定义
其本质就是Java中的重写父类方法
子类重新定义父类的同名函数,即子类与父类函数名相同的情况,称为函数的重定义。
这个操作会使父类的所有重名函数都会被屏蔽(假设父类有重载),常常用于父类该函数不能满足需求时进行的函数重写
(2)调用父类重名函数
① 概述
虽然子类对父类的函数进行了重写,但仍然可以通过为函数名添加作用域的形式使用父类的重名函数
格式:
子类对象.父类名::重名成员名
② 示例
#include
using namespace std;
class Father {
public:
int num;
public:
Father(){}
Father(int num){
this -> num = num;
}
void fun(){
cout << "父类的函数" <