抽象基类(第 13 章)
目录
🔴纯虚函数
🔺在虚函数声明末尾加 = 0,该函数为纯虚函数,类变为抽象类
class Shape {
public:
virtual double area() = 0; // 纯虚函数,无需实现
virtual void draw() = 0; // 纯虚函数
virtual ~Shape() // 析构函数仍需是虚函数
};🔺纯虚函数可以有实现体(少见),但派生类仍必须重写:
virtual void func() = 0; // 声明为纯虚
void Base::func() { /* 可以有实现,但派生类必须重写 */ }🔴抽象类的规则
🔺含有至少一个纯虚函数的类是抽象类:
- 不能实例化:
Shape s;❌ 编译错误 - 可以有指针/引用:
Shape* p = new Circle();✅ - 派生类必须实现所有纯虚函数,否则派生类也是抽象类,同样不能实例化
class Circle : public Shape {
double r;
public:
Circle(double r) : r(r) {}
double area() override { return 3.14159 * r * r; } // ✅ 实现纯虚函数
void draw() override { cout << "Drawing circle\n"; }
};
// Shape s; // ❌ 抽象类不能实例化
Shape* p = new Circle(5.0); // ✅ 基类指针指向派生类对象
cout << p->area(); // 动态绑定,调用 Circle::area
delete p;🔺若派生类只实现了部分纯虚函数,该派生类仍是抽象类:
class PartialShape : public Shape {
public:
double area() override { return 0; }
// draw() 未实现 → PartialShape 仍是抽象类
};
// PartialShape ps; // ❌ 仍不能实例化🔴抽象类的用途
🔺定义接口规范:强制所有派生类实现特定方法,保证多态行为一致
class Animal {
public:
virtual void speak() = 0; // 所有动物必须实现 speak
virtual void move() = 0; // 所有动物必须实现 move
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void speak() override { cout << "Woof\n"; }
void move() override { cout << "Run\n"; }
};
class Bird : public Animal {
public:
void speak() override { cout << "Tweet\n"; }
void move() override { cout << "Fly\n"; }
};
// 统一接口处理不同类型
void makeAnimalAct(Animal* a) {
a->speak(); // 动态绑定,自动调用正确的实现
a->move();
}🔴纯虚函数 vs 虚函数
| 特性 | 虚函数 | 纯虚函数 |
|---|---|---|
| 语法 | virtual void f() | virtual void f() = 0 |
| 有无默认实现 | 有 | 无(= 0) |
| 派生类是否必须重写 | 否(可继承默认实现) | 是(否则派生类也是抽象类) |
| 类能否实例化 | 能 | 不能(含纯虚函数 = 抽象类) |
| 用途 | 提供默认行为,允许重写 | 定义接口,强制派生类实现 |
本节小结
| 要点 | 说明 |
|---|---|
| 纯虚函数 | = 0,无需实现,强制派生类重写 |
| 抽象类 | 含纯虚函数,不能实例化,但可以有指针/引用 |
| 派生类必须全实现 | 未实现所有纯虚函数的派生类仍是抽象类 |
| 接口设计 | 抽象基类用于定义统一接口,配合多态使用 |