在C++的面向对象编程体系里,函数继承是让派生类复用基类成员函数、实现多态特性的重要手段,而抽象基类是函数继承场景中非常特殊的存在,它不能被直接实例化,主要作用是给所有派生类定义统一的接口规范。下面我们通过具体示例来学习抽象基类的定义和使用方法。

什么是抽象基类
抽象基类是指包含至少一个纯虚函数的基类,它无法创建自己的对象实例,只能作为其他派生类的父类存在。抽象基类的核心价值是定义一套所有派生类都必须遵循的接口规则,保证继承体系下的派生类都具备某些统一的行为能力。
如何定义抽象基类
定义抽象基类的核心是声明纯虚函数,纯虚函数的声明格式是在虚函数声明的末尾加上= 0,不需要提供函数实现(也可以提供默认实现,但通常不这么做)。
下面是一个表示图形的抽象基类示例,它定义了获取面积和周长的纯虚函数:
#include <iostream>
using namespace std;
// 抽象基类:图形类
class Shape {
public:
// 纯虚函数:计算面积,派生类必须重写
virtual double getArea() = 0;
// 纯虚函数:计算周长,派生类必须重写
virtual double getPerimeter() = 0;
// 普通虚函数:打印图形信息,派生类可选择重写
virtual void printInfo() {
cout << "这是一个图形" << endl;
}
// 基类析构函数需要声明为虚函数,避免内存泄漏
virtual ~Shape() {}
};派生类如何使用抽象基类
派生类继承抽象基类之后,必须重写基类中所有的纯虚函数,否则派生类也会变成抽象基类,无法被实例化。重写纯虚函数时,函数签名需要和基类中的声明完全一致,包括返回值类型、参数列表和const修饰符等。
我们以圆形和矩形为例,演示派生类如何继承上面的Shape抽象基类:
// 派生类:圆形,继承Shape抽象基类
class Circle : public Shape {
private:
double radius; // 圆半径
public:
// 构造函数
Circle(double r) : radius(r) {}
// 重写纯虚函数:计算圆面积
double getArea() override {
return 3.14159 * radius * radius;
}
// 重写纯虚函数:计算圆周长
double getPerimeter() override {
return 2 * 3.14159 * radius;
}
// 重写普通虚函数:打印圆信息
void printInfo() override {
cout << "这是一个圆形,半径为:" << radius << endl;
}
};
// 派生类:矩形,继承Shape抽象基类
class Rectangle : public Shape {
private:
double width; // 矩形宽
double height; // 矩形高
public:
// 构造函数
Rectangle(double w, double h) : width(w), height(h) {}
// 重写纯虚函数:计算矩形面积
double getArea() override {
return width * height;
}
// 重写纯虚函数:计算矩形周长
double getPerimeter() override {
return 2 * (width + height);
}
// 重写普通虚函数:打印矩形信息
void printInfo() override {
cout << "这是一个矩形,宽为:" << width << ",高为:" << height << endl;
}
};抽象基类的函数继承使用示例
定义好抽象基类和派生类之后,我们就可以通过基类指针或引用来操作派生类对象,实现多态调用,这也是抽象基类函数继承的典型使用场景。
int main() {
// 基类指针指向派生类对象,实现多态
Shape* shape1 = new Circle(5.0);
Shape* shape2 = new Rectangle(4.0, 6.0);
// 调用重写后的函数,会根据对象实际类型执行对应实现
shape1->printInfo();
cout << "圆面积:" << shape1->getArea() << endl;
cout << "圆周长:" << shape1->getPerimeter() << endl;
cout << endl;
shape2->printInfo();
cout << "矩形面积:" << shape2->getArea() << endl;
cout << "矩形周长:" << shape2->getPerimeter() << endl;
// 释放内存,基类析构函数是虚函数,会正确调用派生类析构函数
delete shape1;
delete shape2;
return 0;
}注意事项
- 抽象基类不能被实例化,尝试创建抽象基类的对象会导致编译错误。
- 派生类必须重写抽象基类中所有的纯虚函数,否则派生类也会成为抽象基类。
- 抽象基类的析构函数一定要声明为虚函数,否则通过基类指针删除派生类对象时,会出现派生类部分资源无法释放的问题。
- 纯虚函数也可以有实现,但是即使有实现,派生类仍然必须重写该函数,基类的实现可以通过作用域运算符显式调用。
总结:抽象基类通过纯虚函数定义了派生类必须实现的接口规范,是实现多态和统一继承体系接口的重要工具,合理使用抽象基类可以让代码结构更清晰,扩展性更强。