【Effection C++】读书笔记 条款40:明智而审慎的使用多重继承

【Effection C++】继承与面向对象设计

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

首先介绍一个个小知识,在C++解析一个名称的时候,首先是名字查找(涉及到作用域),然后是类型匹配,从中找到最佳匹配,最后是检查可用性(private,protected,public等)。

1. 多重继承比单一继承要复杂,它很有可能导致歧义。

示例如下:

class Base1
{
public:
    void fun(){}
};

class Base2
{
private:
    void fun(){}
};

class Derived : public Base1, public Base2
{};

int main()
{
    Derived d;
    d.fun();    //错误:对fun的调用有歧义
    return 0;
}

这个例子展现两个知识点:

  1. 多重继承的情况下,很容易造成名字的歧义,使得我们对类的维护增加了困难。
  2. 解析函数调用时候,先名字查找,然后寻找最佳类型匹配,最后判断可用性。因为Base1和Base2中的fun的fun的匹配度一样好,就会直接抛出错误,而不是等到下一步。

改进方法,可以在Derived内显示声明需要调用的函数

class Derived : public Base1, public Base2
{
public:
    void fun()
    {
        Base1::fun();   //显示声明消除歧义
    }    
};

int main()
{
    Derived d;
    d.fun();        //OK
    return 0;
}

2. virtual继承及其带来的复杂性

多重继承除了可能导致更多的歧义以外,还需要注意到的就是是否需要虚继承。

考虑这样一种情况,对于基类A,类B和类C都继承于A,类D又同时继承了B和C(多重继承),那么在类D中是应该具有一份A还是两份A呢?

class A
{};

classs B:public A   //B中有一份A
{};

classs C:public A   //C中有一份A
{};

classs D:public B,public C  //D中有份A
{};

对于C++而言,默认的情况就是D中存在这两份A,但是,在实际生活中,经验往往告诉我们一个D中只有一份A。

但如果在继承的时候加了采用虚继承的方式,像下面这样:

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

那么D中就只有一份A了。

虚继承的要求在于,所有直接继承自基类的classes都采用“virtual 继承”的方式,这样子再对这些类进行多重继承的时候,就会在最底层的派生类中只有一份基类了。

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

从正确行为的观点来看,public继承几乎总应该是virtual的。但是为了支持virtual,编译器必须做更多幕后工作,由此而来带来的后果就是:

使用virtual继承的那些classes所产生的对象往往比使用non-virtual继承的兄弟们体积大,访问virtual base classes的成员变量时,也比访问non-virtual base classes的成员变量速度慢。除此之外,virtual base的初始化职责是由继承体系中的最底层class负责。

所以作者对于virtual base classes的忠告是:

  1. 非必要不使用virtual classes继承,平常请使用non-virtual classes继承

  2. 如果必须使用virtual base classes,尽可能避免在其中放置数据。这样子可以不用担心其初始化和赋值操作。

3. 多重继承的确有正当用途

多重继承有其复杂性,但是在一定情况下也是有着其的用途的。在Effective C++一文中就提出了一个例子,主要就是“public继承某个Interface class” 和 “private 继承某个协助实现的class”的两相组合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值