一、什么叫做抽象类1、 定义抽象类英文名称Abstract Class是指包含至少一个纯虚函数Pure Virtual Function的类。纯虚函数是一种未提供具体实现、仅声明接口的虚函数语法为virtual 返回类型 函数名(参数列表) 0; // 0 表示纯虚函数抽象类的核心作用是定义接口规范强制派生类实现其声明的接口自身无法实例化对象不能创建抽象类的对象。一段比较专业化的解释给大家看的云里雾里继续阅读下大家就会了解了。下面我们一步一步拆解出来看1.1 、是指包含至少一个纯虚函数Pure Virtual Function的类先来了解什么是纯虚函数纯虚函数的前提是必须是一个虚函数即使用关键字Virtual修饰的函数。而纯这个性质则使用赋值等于0的表达式来实现。virtual 返回类型 函数名(参数列表) 0; // 0 表示纯虚函数如定义一个返回值int类型的包含一个参数x的纯虚函数virtual int PV_Fun(int x) 0; // 0 表示纯虚函数这里指出一个纯虚函数是可以有返回值的如果不想要返回值直接定义为void即可这里需要注意虚函数从函数功能上来说可以分为1纯虚成员函数2纯虚析构函数1.2、纯虚函数是一种未提供具体实现、仅声明接口的虚函数未提供具体实现还是以1.1中的代码为例virtual int PV_Fun(int x) 0;注意看赋值号0这是纯的定义这里有C语言基础的同学就会问这里虚纯函数怎么成为左值了回到1.1中括号里补充的说明这里的不是赋值号记住这点即可。不提供具体实现那么我定义这个函数的作用是什么喃另外我需不需要在其他地方提供具体实现先回答确实需要在其他地方提供具体实现。就是在这个类的子类中提供具体实现看代码class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double area() override { // 实现基类的纯虚函数 return 3.14 * radius * radius; } };double area() override { // 实现基类的纯虚函数return 3.14 * radius * radius;}这段代码就是提供了具体的实现再强调一遍这里的定义可以在前面加上virtual或者不加在{}前加上关键字override即说明是对虚函数具体的实现。代码编译时会自动生成虚函数表。此外还有两点需要注意必须被继承抽象类的意义在于通过派生类实现其纯虚函数从而实现多态。派生类需实现所有纯虚函数若派生类未完全实现基类的纯虚函数则该派生类仍为抽象类也不能实例化。1.3 抽象类中提供了接口这句话该如何理解先看一段资料中的解释“抽象类定义模块间的交互接口确保不同实现类遵循统一规范”我们还是以上面代码为例在图形库中Shape作为抽象类定义area()计算体积、draw()画出图形等接口派生类Circle、Rectangle分别实现具体逻辑这也很好理解circle是圆形面积计算公式是piR平方Rectangle是矩形面积计算公式是宽*长。具体画法上更是不同。所以这两个函数必须在具体的类中实现。此时又会有人问那只要定义一个虚函数也就能实现这样的功能为什么还要搞一个抽象类还要搞一个纯虚函数。这就涉及到1.2最后讲解的两个注意点这两点语法就规定了抽象类必须被继承不然编译错误派生类需实现所有纯虚函数。这两点就是不能虚函数无法比拟的。以工作的场景为例基类是领导派生类是他底下的员工。使用虚函数实现多态就像是领导事无巨细的管所有事务它会给派生类说今天干什么事然后自己干一遍让员工跟着这个模板干。而抽象类的领导则是我只管布置任务具体怎么实现它不会干预。本质上来说这种不干预的机制下只要员工能力合格工作上的效率会更高。1.4 抽象类的其他操作与应用这一点很重要我们之前说抽象类无法被实例化但是可万万没说抽象类不能被定义为指针。直接看代码int main() { Shape* shape new Circle(2.0); // 基类指针指向派生类对象多态 cout Area: shape-area() endl; // 调用Circle的area() delete shape; return 0; }Shape* shape则是定义了一个抽象类的指针然后将这个基抽象类指向其派生类。。以下内容抽象类可以正常包含需要注意正常的成员变量、普通成员函数虚或非虚、静态成员嵌套其他抽象类、正常类包含结构体、共用体等复合类型。二、抽象类中的比较特殊的纯虚析构函数2.1. 定义纯虚析构函数是指被声明为纯虚函数的析构函数语法为class Base { public: virtual ~Base() 0; // 纯虚析构函数 };注意纯虚析构函数必须提供定义这是它与普通纯虚函数的关键区别否则会导致链接错误。定义方式为类外实现Base::~Base() { // 纯虚析构函数的定义 // 释放基类资源若有 }这里的代码可能有点误导人注意这个纯虚析构函数的定义一定要放在class外且不能放在其他class中2.2. 核心特性使类成为抽象类包含纯虚析构函数的类是抽象类即使没有其他纯虚函数无法实例化。示例class Base { public: virtual ~Base() 0; // 纯虚析构函数使Base成为抽象类 }; Base::~Base() {} // 必须定义 int main() { Base b; // 编译错误抽象类不能实例化 return 0; }同时具备虚析构函数的特性纯虚析构函数本质是虚析构函数即释放内存因此在多态场景中通过基类指针删除派生类对象时会正确调用派生类析构函数再调用基类析构函数包括纯虚析构的定义避免资源泄漏。示例class Base { public: virtual ~Base() 0; // 纯虚析构函数同时是虚析构 }; Base::~Base() { // 定义纯虚析构 cout Base destructor called endl; } class Derived : public Base { private: int* data; public: Derived() : data(new int) {} ~Derived() override { // 派生类析构自动为虚函数 delete data; cout Derived destructor called endl; } }; int main() { Base* ptr new Derived(); // 基类指针指向派生类对象 delete ptr; // 多态删除 return 0; }输出结果Derived destructor called // 先调用派生类析构 Base destructor called // 再调用基类纯虚析构的定义注意和构造函数的继承不一样构造是先调用基类基类调用完成再来调用派生类的构造函数。此外还需要注意:构造函数是不存在“虚”的状态更不存在“纯虚”状态。2.3. 为什么需要纯虚析构函数主要用于两种场景的结合需要将类定义为抽象类禁止实例化但类中没有其他适合作为纯虚函数的接口即类的核心逻辑不需要其他纯虚函数同时需要确保析构函数的多态性避免派生类资源泄漏。例如一个作为接口的基类仅需要派生类实现构造逻辑而无需其他接口但又必须禁止基类实例化此时可用纯虚析构函数。4. 常见误区误以为纯虚析构函数可以不定义普通纯虚函数如virtual void f() 0可以不定义由派生类实现但纯虚析构函数必须定义。因为派生类的析构函数会自动调用基类析构函数若基类纯虚析构无定义链接时会报错未找到函数实现。混淆纯虚析构与普通虚析构纯虚析构是 “纯虚 虚析构” 的结合既让类抽象又保证析构多态普通虚析构仅保证析构多态不使类抽象。三、抽象类与纯虚析构函数的关系纯虚析构函数是抽象类的一种特殊情况包含纯虚析构函数的类必然是抽象类抽象类不一定需要纯虚析构函数多数抽象类通过其他纯虚函数如area()、run()成为抽象类仅在特殊场景下使用纯虚析构。总结抽象类是含纯虚函数的类用于定义接口禁止实例化需派生类实现接口纯虚析构函数是特殊的纯虚函数既使类成为抽象类又保证析构多态性且必须提供定义两者结合可满足 “接口抽象 析构安全” 的设计需求是 C 多态和资源管理的重要工具。