到底什么才算是oo里的继承

Dec 1, 2013


前天大半夜的群里在讨论什么才是oo里的继承这个问题,突然才想起来这么一个重要的问题。之前也一直都是在使用继承,但却从来没有思考过所谓oo里的继承,什么才是oo里的继承。

oo当然是物向导论的,而我们讨论的问题就是在物向导论中什么才是继承。这就是一个命题讨论了。

Effective c++中的item 32里明确解释了何为继承:A与B有明确的is-a关系时就是继承。关于is-a概念,大家可以翻阅item 32里对于is-a的解释。但是经过大家的讨论,对于is-a的讨论略多而且对这种概念略微质疑。

吃个栗子,鸟会飞,企鹅是鸟,但是企鹅不会飞,这样在is-a关系中似乎有些矛盾。有基类:class Bird,在Bird类中有fly()方法,但是企鹅是鸟,于是我们便以为可以做这样做:

class Penguin : public Bird{};

当我们调用(不管我们是否知道) Penguin.fly();的时候,麻烦来了,Penguin根本是不会飞的,但是Penguin是鸟!这里有is-a关系了,但是根据is-a关系得到继承关系却会出错(尽管我们可以人为的在编译期或者运行期阻止这种错误)。或许有人说,我知道Penguin不会飞,我也不会去调用fly()这个方法,我实例化Penguin是有别的用处,但是这种情况遵照is-a的说法是错误的,也就是说,当前的is-a没有理解我们的需求。这种理解是基于人对于is-a的理解上的,因为本身鸟会飞就是一个伪命题。

那到底什么才是继承呢?因为现实世界里类似的伪命题很多。实际上严格对于继承来说,是抽取共性,还有一种就是继承接口。所谓抽取共性,我想这个就很好明白了。将不同物体的相同性质抽取出来。A与B在width和height相同,按照oo的思想将这个共性抽出来单独形成class Base;然后分别 class A :public Base;public B:public Base;然后单独去实现A和B非共性部分,比如说shape等。这里就算是一种正确的is-a关系,与上面的栗子不同,上面的栗子含有伪命题,所以对于is-a来说并非就是完全等价于继承的。

再来说说继承接口,一直觉得继承接口这种说法是错误的。看到这个脑海里就会想到哪有什么is-a关系啊,这也不是继承啊。所以我觉得应该叫实现接口更为恰当。既然是接口当然是pure virtual,“继承接口”是不存在is-a关系的,同时也没有任何共性的。当然c++没有明确的接口概念那就另说了。