继承
在你编写代码解决实际问题时,经常能找到一些已有的类,它们能够实现你所需的大部分功能,但不是全部。这时该怎么办?当然,你可以对这个已有的类进行修改,但这么做很容易让代码变得更加复杂,一不留神就可能会破坏原来可以正常工作的功能。
当然,也可以另起炉灶重新编写一个类:复制粘贴原来的代码再融入自己的新代码。但这意味着你需要维护更多的代码。同时,新类和旧类中实现同样功能的代码被分隔在了不同的地方(日后修改时需要改动多处)。
更好的解决方法是利用类的继承:从已有类中衍生出新的类,添加和修改部分功能。这是代码复用的一个绝佳的例子。使用继承得到的新类会自动获得旧类中的多有方法,而不需要进行任何复制。
你只需要在新类里面定义自己额外需要的方法,或者按照需求对继承的方法进行修改即可。修改得到的新方法会覆盖原有的方法。我们习惯将原始的类称为父类、超类或基类,将新的类称作孩子类、子类或衍生类。这些术语在面向对象的编程中不加以区分。
现在,我们来试试继承。首先,定义一个空类 Car。然后,定义一个 Car 的子类 Yugo。定义子类使用的也是 class 关键字,不过需要把父类的名字放在子类名字后面的括号里:
接着,为每个类创建一个实力对象:
子类是父类的一种特殊情况,它属于父类。在面向对象的术语里,我们经常成 Yugo 是一个 Car。 对象 give_me_a_yugo 是 Yugo 类的一个实例,但它同事集成了 Car 能做到的所有事情。当然,上面的例子中 Car 和 Yugo 就像潜艇上的甲板水手一样起不到任何实际作用。我们来更新一下类的定义,让它们发挥点儿作用:
最后,为每一个类各创建一个对象,并调用刚刚声明的 exclaim 方法:
我们不需要进行任何特殊的操作,Tesla 就自动从 Car 那里继承了 exclaim() 方法。但事实上,我们并不希望 Tesla 在 exclaim() 方法里面宣称它是一个 Car,这可能会造成无法区分 Car 和 Tesla。让我们来看看怎么解决这个问题。
覆盖方法
新创建的子类会自动继承父类的所有信息。接下来我们来看子类如何替代——覆盖(override)父类的方法。
为每个类创建一个对象:
执行看下结果:
我们覆盖了父类的 exclaim() 方法。 在子类中,可以覆盖任何父类的方法,包括 init()。下面我们使用之前的 Person 类。我们来创建两个子类,分别代表医生(MDPerson)和律师(JDPerson)
在上面的例子中,子类的初始化方法 init() 接受的参数和父类 Person 一样,但存储到对象内部 name 特性的值却不尽相同:
下周见
领取专属 10元无门槛券
私享最新 技术干货