OOP 基础知识:继承

在构建大型复杂项目时,人们总是寻求提高效率的方法。一种流行的方法是利用现有的开发成果。例如,开发一个建筑规划,基于之前的蓝图比从零开始要容易得多。

代码复用在编程中也非常流行。我们已经知道这样一种技术:将一段代码隔离成一个函数,然后在需要相应功能的不同位置调用函数。但 OOP 提供了一种更强大的机制:在开发一个新类时,它可以继承自另一个类,从而获得所有内部结构和外部接口,只需进行最小限度的调整即可满足需求。因此,从父类开始,您可以快速扩展一个具有附加或改进功能的派生类。此外,对父类的任何后续更改(例如增强功能或 bug 修复)都会自动影响所有子类。

如果一个类是另一个类的父类,则前者被称为基类。反过来,从基类继承的类被称为派生类。

当然,继承链(或者更形象地说,家谱)可以延续:每个类可以有多个继承人,这些继承人又有各自的继承人,依此类推。继承规则唯一不允许的是亲属关系的循环,例如,孙子不能成为祖父的父亲。

任何类与其任何一代的后代之间的关系都用“是 (is a)”这个词来描述,也就是说,后代可以充当祖先,但反之则不行。这是因为派生对象实际上包含祖先的数据模型,并为其添加了新的字段和行为。

通过相互继承类,我们有机会以统一的方式处理相关对象,因为它们的某些功能是通用的。

例如,假设一个绘图程序可以用来实现多种类型的形状,包括圆形、正方形、三角形等等。每个对象在屏幕上都有坐标(为简单起见,我们假设指定了形状中心的一对 X 和 Y 值)。此外,每个形状都使用自己的背景颜色、边框颜色和边框粗细进行渲染。

这意味着我们只需在描述抽象形状的父类中实现一次设置坐标和设置绘制样式的函数,这些函数就会自动被所有后代继承。

此外,为了简化源代码,不仅希望统一设置,也希望统一不同形状的绘制。这句话包含某种矛盾:既然形状各不相同,而且每种形状都必须以自己的方式显示,那么我们所说的统一究竟是什么呢?我们所说的是统一软件接口。确实,根据“抽象”的概念,有必要将外部接口与内部实现分离。而具体形状的显示本质上是一个实现细节。

统一的接口和针对不同形状类型的不同实现,顺理成章地引出了下一个概念:多态性。