EffectiveC++学习笔记-条款39|40

来源:互联网 发布:中控iface702软件 编辑:程序博客网 时间:2024/05/29 07:12

条款39 明智而审慎的使用private继承
条款40 明智而审慎的使用多重继承

明智而审慎的使用private继承

private继承的意义在于“be implemented in turns of”,这个与上一条款中说的复合模型的第二层含义是相同的,这也意味着通常我们可以在这两种设计方法之间转换,但书上还是更提倡使用复合来进行类的设计。

private继承与public的继承是完全不同的,主要体现在两个地方:

其一,public继承在子类中保持父类的访问权限,即父类中是public的成员函数或成员变量,在子类中仍是public,对private或者protected的成员函数或成员变量亦是如此;但private继承则不是这样了,它破坏了父类中的访问权限标定,将之都转成private,这对子类本身并无影响(照常访问),但却影响了子类的子类,子类的子类将无法访问这些声明/定义在爷爷辈类的成员变量或成员函数。

其二,Liskov法则不再适用,也就是说“一切父类出现的地方都可以被子类所替代”的法则在private这里不成立

当然私有继承也是可以替换的,例如:

class Widget:private Timer{private:    virtual void onTick() const;}//可以使用内部类替换class Widget{private:    class WidgetTimer:public Timer    {    public:        virtual void onTick() const;    }    WidgetTimer timer;}

空白基类优化

一个正常的类class Empty{};即使没有任何内容也会有空间存在。大多数的编译器sizeof(Empty) = 1此时继承时:

class HoldAnInt{private:    int x;    Empty e;}sizeof(HoldAnInt) > sizeof(int) //!class HoldAnInt : private Empty {private:    int x;}sizeof(HoldAnInt) == sizeof(int) //!

非常在意空间使用时,可以特别注意EBO(empty base optimization;空白基类最优化)

总结

  • private继承意味着is-implemented-in-terms of(根据某物实现出)通常比复合的级别低。
  • 但是derived class需要访问protected base class的成员,或者重新定义继承而来的 virtual的函数,这么设计是合理的。
  • 另外就是注意空白基类最优化

明智而审慎的使用多重继承

多重继承是一种比较复杂的继承关系,它意味着如果用户想要使用这个类,那么就要对它的父类也了如指掌,所以在项目中会带来可读性的问题,一般我们都会尽量选择用单继承去替代它。

使用多重继承过程容易碰到的问题就是名字冲突,像下面这样:

class BorrowableItem    //图书馆允许借的东西{public:    void checkOut() //离开时检查    {        cout << "BorrowableItem checkOut" << endl;    }};class ElectronicGadget{private:    bool checkOut() const   //执行自我检查    {        cout << "ElectronicGadget checkOut" << endl;        return true;    }};//多重继承  class MP3Player : public BorrowableItem,    public ElectronicGadget{};int main(){    MP3Player mp;    mp.checkOut();    return 0;}//报错信息error C2385: 对“checkOut”的访问不明确note: 可能是“checkOut”(位于基“BorrowableItem”中)note: 也可能是“checkOut”(位于基“ElectronicGadget”中)

修改的方法

    MP3Player mp;    mp.BorrowableItem::checkOut();   //声明自己需要哪一个父类的成员    //但是使用ElectronicGadget的成员就不可以了     error C2248: “ElectronicGadget::checkOut”: 无法访问 private 成员(在“ElectronicGadget”类中声明)

多重继承另一个容易碰到的问题就是虚继承。试想一下,有一个父类名为A,类B和类C都继承于A,类D又同时继承了B和C(重继承),那么如果不做任何处理,C++的类继承图里会包含两份A。

但如果在继承的时候加了virtual,像下面这样:

class B: virtual public A{…}class C: virtual pulibc A{…}

那么D中就只有一份A了。C++标准库里面的流就是采用这样的形式,有一个父流basic_ios,basic_istream和basic_ostream分别虚继承于basic_ios,而basic_iostream又多重继承于basic_istream和basic_ostream

为了保证不会出现两份父类,只要是public继承理论上都应该有virutal关键字,但virutal也是有代价的,访问virtual base class的成员变量要比访问non-virutal base class的成员变量速度要慢。所以作者的忠告是:

  1. 非必要不使用virtual classes继承,普通情况请使用non-virtual classes继承
  2. 如果必须使用virtual base classes,尽可能避免在其中放置数据。

最后总结一下

  1. 多重继承比单一继承更复杂。它可能导致新的歧义性,以及对virtual继承的需要。
  2. virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将是最具实用值的情况。
  3. 多重继承的确有正当用途。其中一个情节涉及”public继承某个Interface class”和”private继承某个协助实现的class”的两组合。