条款40:明智而审慎地使用多重继承

1、关于MI 和 SI的两个观点

MI 多重继承,SI单一继承。C++开发者分为两派,一派认为如果单一继承是好的,那么多重继承一定是更好的,即,支持多重继承。但是另一派认为,单一继承是好的,但是应该尽量少用多重继承,即不支持多重继承。

2、多重继承可能引发的问题:名称歧义

(1)引发歧义举例
    clas BorrowableItem{
    public:
        void checkOut();
        ……
    };
    class ElectronicGadgent{
    private:
        bool checkOut() const;
        ……
    };

    class MP3Player: public BorrowableItem, public ElectronicGadget
    {
        ……
    };
    MP3Player mp;
    mp.checkOut();//歧义,调用哪个checkOut?
(2)为什么引发歧义?

虽然上面两个函数一个是public,一个是private,但还是有歧义。

这与C++用来解析(resolving)重载函数调用的规则相符:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用是最佳匹配。上面两个checkOut有相同匹配度。为了解决歧义,必须指明调用哪一个base class内的函数

(3)解决名称歧义的方法

调用时写清楚调用的函数版本,符合编译器规则就能够被正确调用。

mp.BorrowableItem::checkOut();	    //成功调用
mp.ElectronicGadgent::checkOut();   //该版本是private的,会导致编译错误

3、钻石性多重继承

(1)什么是钻石型多重继承?

举例:
在这里插入图片描述

(2)钻石型多重继承面临的问题:subclass 应该拥有几份baseclass的成员?
  • 从逻辑上来讲,应该拥有一份,例如上述描述的是文件,那么文件应该只有一个名字。
  • 从继承关系上来讲,应该拥有两份。
(3)C++支持的解决钻石型多重继承问题的两个方案

C++对上述两种角度都支持,缺省情况下,C++支持的是拥有两份。

如果你需要的设计是拥有一份,那么可以通过:另base class virtual类,派生类由public继承,改为采用virtual public继承 这两个点来实现此需求。(C++标准程序库中确实含有一个这样的继承体系。)

4、关于pubilc virtual继承

virtual 的成本:
  • virtual 继承的classnon-virtual继承的class体积要大、访问成员变量的速度也相比较慢,此种细节因编译器不同而异。
  • virtual 继承的初始化及赋值情况复杂,且不直观。

5、对于virtual base classes的忠告

  • 如非迫不得已,不使用virtual继承。
  • 必须使用virtual 继承时,virtual base classes 类中尽可能不要放置成员变量,以避免初始化为题。(即:定义成virtual接口类。)

总结:

多重继承只是面向对象的一个工具而已。和单一继承比较,它比较复杂,也难以理解,所以如果有一个单一继承方案和一个多重继承方案,那么单一继承方案比较受欢迎。但是如果通过多重继承可以完成任务,而且最简洁、最易维护、最合理,那么就不用怕使用它。

多重继承的确有正当用途。其中一个情节设计public继承某个Interface classprivate继承某个协助实现的class

posted @ 2019-12-24 15:41  江南又一春  阅读(119)  评论(0编辑  收藏  举报