面向对象方法的基本机制有:封装、继承和重定义。封装表示数据和操作被封装在一个类里,继承是子类对父类属性和操作的继承,重定义是子类对父类中某个成员方法的重定义。我们的问题是:重定义的本质是什么?
以Python为例,看下面一段代码:
打印结果:
in Parent.mm()
in Child.mm()
这个例子给我们这样一个感觉:重定义就是子类在继承父类的方法时,改变了它在父类中的行为。这话没有错误,但是不够深刻,也解释不了重定义为什么存在的原因。如果你仅仅只是想在子类中改变父类对某个方法的缺省定义,你完全可以另外定义一个新方法mm2():
这样打印出来的结果完全一样,更重要的是,代码似乎更加容易理解一些。既然如此,那我们要问:重定义存在的真正理由是什么?有什么是重定义能做而其他机制做不了的?
答案是:重定义能够间接地改变父类的行为。
打印结果是:
123
xyz
例子中,子类并没有重定义ff()方法,而是重定义了mm()方法。而父类中ff()调用了mm()方法,所以子类的重定义间接改变了ff()的行为。
可能你会说,那我也在子类中定义一个ff2()方法不也行吗?不行。因为面向对象方法的第一个机制就是封装,所以很多情况下我们只知道对象obj里有一个方法ff(),并不清楚它的实现,更不知道或者说不需要知道函数mm()的存在。何况,迫使使用方不但要记住ff()方法还要记住方法ff2(),增加了使用者的负担。下面再给出一个例子:
这个例子中父类Goods给出了商品的缺省价格(1.0)和缺省数量(1),get_sum()函数则计算商品的总金额。子类Car和Chopstick分别重定义了价格和数量,因为人们买车的时候一般只买一辆,而买筷子的时候一般一买一打,最后打印出来的总金额就是:20000 , 12.0。
这里我们仅仅只是根据汽车和筷子的性质描述了Car和Chopstick类,但却间接改变了他们各自的求总金额操作,这个例子再一次证明了重定义的优雅和威力。