C++黑马程序员——P138,140. 纯虚函数和抽象类,虚析构和纯虚析构
- P138. 类和对象——多态——纯虚函数和抽象类
- P140. 类和对象——多态——虚析构和纯虚析构
- P138. 纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为 纯虚函数
纯虚函数语法: virtual 返回值类型 函数名 (参数列表) = 0;
当类中有了纯虚函数,这个类称为抽象类
抽象类特点:
● 无法实例化对象
● 子类必须重写抽象类(父类)中的纯虚函数,否则也属于抽象类
1 //纯虚函数和抽象类
2 class Base
3 {
4 public:
5 //纯虚函数
6 //只要有一个纯虚函数,这个类就是抽象类:无法实例化对象
7 virtual void func() = 0;
8 };
9
10 class Son :public Base
11 {
12 public:
13 //子类必须重写父类中的纯虚函数,否则也属于抽象类
14 virtual void func()
15 {
16 cout << "Son 的 func() 调用" << endl;
17 }
18 };
19
20 void test01()
21 {
22 //Base b1; //报错,抽象类无法实例化对象
23 //new Base; //报错,抽象类无法实例化对象,堆区也不行
24
25 //使用 多态 调用子类的函数
26 Base* base = new Son;
27 base->func();
28 }
29
30 int main()
31 {
32 test01();
33 return 0;
34 }
运行结果:
- P140. 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为 虚析构 或者 纯虚析构
虚析构和纯虚析构共性:
● 可以解决父类指针释放子类对象
● 都需要有具体的函数实现
虚析构和纯虚析构区别:
● 如果是纯虚析构,该类属于抽象类,无法实例化对象
1 class Animal
2 {
3 public:
4 Animal()
5 {
6 cout << "Animal 构造函数调用" << endl;
7 }
8
9 ~Animal()
10 {
11 cout << "Animal 析构函数调用" << endl;
12 }
13
14 //纯虚函数
15 virtual void speak() = 0;
16 };
17
18 class Cat:public Animal
19 {
20 public:
21 Cat(string name)
22 {
23 cout << "Cat 构造函数调用" << endl;
24 m_Name = new string(name);
25 }
26
27 ~Cat()
28 {
29 cout << "Cat 析构函数调用" << endl;
30 if (m_Name != NULL)
31 {
32 delete m_Name;
33 m_Name = NULL;
34 }
35 }
36
37 virtual void speak()
38 {
39 cout << *m_Name << " Cat speak" << endl;
40 }
41 string* m_Name;
42 };
43
44 void test01()
45 {
46 Animal* animal = new Cat("Tom");
47 animal->speak();
48 delete animal;
49 }
50
51 int main()
52 {
53 test01();
54 return 0;
55 }
运行结果:
出现的问题:释放 animal 指针时,没有调用子类中的析构函数,子类中堆区的数据(m_Name)没有被释放,导致内存泄漏。(父类指针在析构时候,不会调用子类中析构函数)
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名()= 0;
类名 :: ~类名(){}(纯虚析构 在类外需要有具体的函数实现)
把上面 Animal 的析构函数改成虚析构:
1 //虚析构; 利用虚析构可以解决 父类指针释放子类对象时不干净的问题
2 virtual ~Animal()
3 {
4 cout << "Animal 析构函数调用" << endl;
5 }
运行结果:
把 Animal 的析构函数改成纯虚析构也可以:
1 class Animal
2 {
3 public:
4 Animal()
5 {
6 cout << "Animal 构造函数调用" << endl;
7 }
8
9 //纯虚析构,需要声明也需要实现 (在类外要有具体的实现,否则运行会报错)
10 //有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
11 virtual ~Animal() = 0;
12
13 //纯虚函数
14 virtual void speak() = 0;
15 };
16
17 Animal::~Animal()
18 {
19 cout << "~Animal 的纯虚析构调用" << endl;
20 }
运行结果:
总结:
1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2. 如果子类中没有堆区数据,可以不写 虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类
(〃>_<;〃)(〃>_<;〃)(〃>_<;〃)
分类:
C++学习笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!