😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 抽象基类 和 纯虚函数 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、纯虚函数
- 🎄三、抽象基类
- 🎄四、为什么需要抽象类
- 🎄五、总结
🎄一、概述
在生活中,有时会使用到比较抽象的词语,例如下面这个场景:
A:帮我把那个“东西”拿过来。
B:你是说,桌面的那个杯子吗?
A:是的。
这个场景中的“东西”就属于抽象的词语。而在C++编程中,有时也会出现这样抽象的语法。例如,我们可能会定义一个“动物”基类,但代码中不会定义一个“动物”的实例,而是将“动物”基类派生出“狗”、“猫”等派生类,再使用派生类去实例化。
本文主要介绍下面几个内容:
1、什么是纯虚函数?
2、什么是抽象基类?
3、为什么需要抽象基类?
🎄二、纯虚函数
上篇文章:【C++ | 虚函数】虚函数详解 及 例子代码演示(包含虚函数使用、动态绑定、虚函数表、虚表指针),我们详细地介绍了虚函数以及C++怎样实现虚函数的,但有一个也是很重要的知识点没在上篇文章介绍,这个知识点就是 纯虚函数。
纯虚函数:本质上也是虚函数,在虚函数的函数原型的分号前加上=0
就可以将一个虚函数说明为纯虚函数。
下面代码声明了一个虚函数 eat:
virtual void eat() =0;
纯虚函数的特点:
1、纯虚函数声明就是在函数原型分号前加=0
;
2、纯虚函数允许只有声明,没有定义(实现);
3、纯虚函数可以没有定义,也可以有定义,但纯虚函数的定义只能在类外。
4、只有虚函数可以加=0
,非虚函数加=0
会编译报错:error: initializer specified for non-virtual method
🌰举例子
// g++ 24_pure_virtual.cpp
#include <iostream>
using namespace std;class CAnimal{
public:// 1、纯虚函数声明就是在函数原型分号前加`=0`// 2、纯虚函数允许只有声明,没有定义(实现);virtual void eat() =0; virtual void run() =0;
};// 3、纯虚函数的定义只能在类外。
inline void CAnimal::run()
{cout << "Animal run" << endl;
}int main ()
{}
🎄三、抽象基类
抽象基类:英文名称是abstract base class
,缩写为ABC
。抽象基类是包含了至少一个纯虚函数
的基类,在代码中只能用来做基类,不能用来实例化对象。
抽象基类虽然不能实例化对象,但可以定义抽象基类的指针或引用,以此来管理其派生类对象。
抽象基类的特点:
1、抽象基类至少有一个纯虚函数;
2、抽象基类不能创建对象;
3、抽象基类要求派生类必须重写纯虚函数,以此来规范派生类的接口(函数);
4、派生类必须重写抽象基类中的所有纯虚函数
,否则也是抽象类,无法实例化对象。
5、抽象基类的纯虚函数一般没有定义,即使有定义也没法创建对象去调用。
🌰举例子
// g++ 24_pure_virtual2.cpp
#include <iostream>
using namespace std;class CAnimal{
public:virtual void eat() =0; // 纯虚函数,本类是抽象基类virtual void run() =0;
};class CCat : public CAnimal{
public:// 没有重写基类的所有纯虚函数,本类是抽象类virtual void eat(){cout << "cat eat" << endl;}
};class CDog : public CAnimal{
public:// 重写基类的所有纯虚函数,本类不是抽象类virtual void eat(){cout << "dog eat" << endl;}virtual void run(){cout << "dog run" << endl;}
};// 纯虚函数的定义只能在类外。
inline void CAnimal::run()
{cout << "Animal run" << endl;
}int main ()
{//CAnimal animal; // 报错:error: cannot declare variable ‘animal’ to be of abstract type ‘CAnimal’//CCat cat; // 报错:error: cannot declare variable ‘cat’ to be of abstract type ‘CCat’CDog dog;CAnimal *pAnimal = &dog;pAnimal->run();pAnimal->CAnimal::run(); // 指定调用基类的run
}
运行结果:
🎄四、为什么需要抽象类
之前一直在想,很多代码明明使用普通类也可以,为什么需要定义抽象类呢?
需要定义抽象基类的几个原因:
- 1、将接口与实现分离。接口是软件产品最有价值的资源,设计接口比实现接口需要耗费更昂贵的成本。因此,要将接口保护起来,以免在针对客户需求修改实现的时候,程序员不小心把接口破坏掉。
我们将一些必要的接口(函数)定义在抽象类,要求派生类必须按照这个格式去重写,如果不重写就休想创建对象。也就是说,抽象类将具体实现延迟到子类中,提供代码重用性和一定程度的设计约束。 - 2、避免某些基类被实例化是不合理的。例如“形状”这个基类,被实例化之后反而会让人相当费解,所以干脆将“形状”这个类定义为抽象类,由它派生出正方形,三角形等子类。
- 3、提示作用,当我们看到抽象基类就会知道其派生类一定会重写纯虚函数,而且也会去找抽象类的指针或引用,看看是否实现多态。其次,看到抽象类也知道它不会定义对象,也就不会去代码里找抽象类的对象了。
🎄五、总结
本文介绍了C++的纯虚函数、抽象基类,以及怎样使用它们,最后介绍了需要抽象基类的原因。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
《C++ primer》
《C++ primer plus》
C++为什么要定义抽象基类?
为什么需要抽象类和接口?
为什么使用抽象类?有什么好处?