12.2 多重继承
我们了解了保证类的继承和类型的机制之间的一致性的难处。类型相当于我们在第 11 章中学习的类的三种作用之中的可行操作的功能说明。
另一方面,发挥类作为代码再利用单元的作用时,类型和类就是分类这种观点有时具有适得其反的效果。尤其对于动态类型语言这样不太重视类型的语言。
本节我们将深入探讨使用类来实现代码再利用的方法。
一种事物在多个分类中
把文件放进不同文件夹进行整理时,常常会有这个或者那个文件该放入哪个文件夹的烦恼。这是因为现实世界中的物并不仅仅属于某一种分类。
举个具体的例子,假设要把公司职员进行分类。把公司职员这个类的元素(即职员)进行分类,定义程序员类,同时也定义不同岗位的业务员类。如果说业务部的职员小李也会编写程序,那究竟该把小李放入程序员类还是业务员类呢?
一个人同时承担程序员和业务员的角色的情况是完全有可能的。那么一个类同时作为多个类的子类的情况就是很自然的了。也就是说现实世界中一种事物有可能属于多种分类。为了实现对这种现实情况的模拟,作为工具的程序设计语言是不是应该支持对多个类的继承呢?这就是多重继承的初衷。
多重继承对于实现方式再利用非常便利
多重继承对于实现方式再利用是一种非常便利的方法。图 12.6 展示的就是多重继承的一个例子。带有菜单栏的窗口这种类继承了窗口类并且实现了菜单栏的操作。另外,带有滚动栏的窗口类也继承了窗口类,并且实现了能滚动内容的滚动栏的功能。如果要实现一种既具有菜单栏又具有滚动栏的窗口该怎么做呢?在支持多重继承的语言中,只需要继承两个类就可以实现。

图 12.6 GUI 和多重继承
另外,作为实际使用的代码的一个例子,我们来看从 Python 语言标准库 SocketServer.py 中取出的四行代码。
Python标准库中使用的多重继承示例
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
这段代码定义了四个子类,用来表示在通信中使用 UDP 还是 TCP 以及并行处理中使用 fork 还是 thread。这四个子类是由两个选项结合两个类做多重继承定义的(图 12.7)。pass 一词的意思是没有特殊的处理。比如定义 ForkingUDPServer 只需要继承 ForkingMixIn 和 UDPServer 就可以完成,不需要其他的代码。

图 12.7 Python 标准库中使用的多重继承
