C++编程规范之37:公用继承即可替换性。继承,不是为了重用,而是为了被重用

摘要:

    知其然:公用继承能够使基类的指针或者实际引用指向某个派生类的对象,既不会破坏代码的正确性,也不需要改变已有的代码。

    还要知其所以然:不要通过公用继承重用(基类中的已有)代码,公用继承是为了被(已经多态地使用了基对象的已有代码)重用的。

    按照Liskov替换原则(LiskovSubstitution Principle),公用继承所建模的必须总是“是一个(is-a)”关系:所有基类约定必须满足这一点,因此如果依靠成功地满足基类的约定,所有虚拟成员函数的改写版本就必须不多于其基类版本,其承诺的也必须不少于其基类版本。使用指向Base的指针或者引用的代码必须能正确工作,即使指针或者应用实际上指向的是Derived。

    继承的误用将破坏正确性。没有被正确实现的继承大多数都会无法遵守基类确定的显式或者隐式约定而迷乱。这种约定可能是很微妙的,如果无法在代码中直接表达,程序员就必须格外小心。

    公用继承的目的是实现可替换性,公用继承的目的并不是为了派生类重用积累的代码,从而用基类代码实现自己。这种“用……来实现”的关系可能完全没有问题,但是应该用组合关系来建模——或者仅仅在某些特殊情况下,通过非公用继承来实现。

    还可以用另一种说法来表述:当动态多态正确而且适合时,组合是自私的,而继承是慷慨的。心的派生类是已有通用抽象的新特例。已有的动态代码通过调用Base的虚拟函数来使用Base&或者Base*,应该能够无缝地使用继承自Base的MyNewDerivedType的对象。心的派生类型向已有代码中添加新功能时,不需要修改已有代码,而是可以在加入新派生对象时无缝地增加其功能。

    新的需求应该很自然地由新代码满足,心的需求不应该导致对已有代码的重新改写。

在面向对象技术出现之前,新代码掉哟个已有代码就一直很容易。尤其是公用继承使已有代码安全无缝地调用新代码变得更加容易了。

你可能感兴趣的:(C++,继承,重用,Liskov替换原则,C++编程规范)