8.5 继承与抽象类
继承表示“是一个”的关系。Food 是一种 Product,Circle 是一种 Shape。C++ 继承很强大,但它不是代码复用的默认答案。只有当调用者应该能通过一个更通用的类型处理多个更具体的类型时,继承才合适。
本节关注类设计本身:基类、派生类、访问权限、构造顺序、override、纯虚函数和抽象接口。下一节再专门讲运行期多态。
基类和派生类
基类保存共享行为,派生类添加或专门化行为。
cpp
class Product {
private:
std::string name_;
double price_;
public:
Product(std::string name, double price)
: name_(name), price_(price) {}
std::string name() const { return name_; }
double price() const { return price_; }
virtual std::string label() const {
return name_ + " $" + std::to_string(price_);
}
};
class Food : public Product {
private:
int calories_;
public:
Food(std::string name, double price, int calories)
: Product(name, price), calories_(calories) {}
std::string label() const override {
return "Food: " + name() + ", " + std::to_string(calories_) + " kcal";
}
};public Product 表示通过 Food 访问时,Product 的 public 成员仍然是 public。派生类构造函数在初始化列表中调用基类构造函数。构造顺序总是先基类、后派生类,因为对象的基类部分必须先存在,派生类部分才能在它的基础上继续构造。
override 不是语法上必须写的,但你应该写。它要求编译器检查这个函数确实重写了基类虚函数。如果你拼错函数名,或不小心改了参数,编译器会立刻发现。
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
纯虚函数和抽象类
有些基类不是为了直接创建对象,而是为了定义接口。
cpp
class Shape {
public:
virtual double area() const = 0;
virtual std::string name() const = 0;
virtual ~Shape() = default;
};= 0 会让函数成为纯虚函数。只要类中至少有一个纯虚函数,这个类就是抽象类,所以下面代码非法:
cpp
Shape shape; // 错误:Shape 是抽象类。派生类只有实现所有纯虚函数后,才会成为可以创建对象的具体类。
cpp
class Circle : public Shape {
private:
double radius_;
public:
explicit Circle(double radius) : radius_(radius) {}
double area() const override {
return 3.1415926 * radius_ * radius_;
}
std::string name() const override {
return "circle";
}
};抽象类适合表达“我承诺有这种行为,但不规定唯一实现”。基类说“每个形状都能报告面积”,派生类决定具体怎么算。
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
谨慎设计继承
继承会让类之间形成长期关系,所以要谨慎设计。
适合使用继承的情况:
- 派生类确实是基类的特殊版本;
- 调用者能从共享接口中受益;
- 基类足够稳定,派生类可以依赖它。
不适合使用继承的情况:
- 你只是想复用几个辅助函数;
- 派生类只是“用到了”基类,而不是“是一种”基类;
- 基类一改,派生类就经常被连带破坏。
组合通常更简单:
cpp
class EmailNotification {
private:
Message message_;
};但如果多种通知都必须提供同一组操作,抽象基类就是干净的选择:
cpp
class Notification {
public:
virtual ~Notification() = default;
virtual std::string preview() const = 0;
};接口保持小而明确,每个派生类都被强制提供必要行为。
正在加载概念检查...
正在加载本节练习...