您的位置:首页 > 编程语言 > C语言/C++

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

2017-05-19 09:50 711 查看

【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;
}


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

多重继承的情况下,很容易造成名字的歧义,使得我们对类的维护增加了困难。

解析函数调用时候,先名字查找,然后寻找最佳类型匹配,最后判断可用性。因为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的忠告是:

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

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

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

多重继承有其复杂性,但是在一定情况下也是有着其的用途的。在Effective C++一文中就提出了一个例子,主要就是“public继承某个Interface class” 和 “private 继承某个协助实现的class”的两相组合。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  effective-c++ c++