C++_代码重用4-多重继承

继承使用时要注意,默认是私有派生。所以要公有派生时必须记得加关键字Public。

MI(Multi Inheritance)会带来哪些问题?以及如何解决它们?

两个主要问题:

       从两个不同的基类继承同名方法;

       从两个或更多相关基类那里继承同一个类的多个实例;

虚方法

Worker公有派生出Singer和Waiter;

然后Singer和Waiter公有派生出SingingWaiter(即多重继承);

这样会导致一个问题,就是SingingWaiter中有两个Worker组件。通常可以将派生类对象的地址赋值给基类指针。但是在这样的情况下这么做的话,将出现二义性。所以必须使用类型转换来指定对象。但这又增加了指针引用的复杂度。

       C++在引入多重继承的同时,也引入新技术——虚基类,来解决该问题。

虚基类也用关键字virtual,虚基类与虚函数之间并不存在明显的联系。这么做是为了给程序员减少压力,类似于关键字的重载。

class Singer: virtual public Worker{…};

class Waiter: public virtual Worker{…};

(virtual和public的次序无关紧要)

 

那么为什么不使虚行为成为MI的默认准则呢?

       在一些情况下,可能需要基类的多个拷贝;

       将基类作为虚的要求程序完成额外的计算,为不需要的程序付出代价是不应当的;

 

新的构造函数规则

       使用虚基类时,必须对构造函数采用新的方法;

       对于非虚基类,唯一可以出现在初始化列表中的构造函数是即时基类构造函数。

A派生B,B派生C;--->C类的构造函数只能调用B类的构造函数,B类的构造函数只能调用A类构造函数。

但对于虚基类而言,这种信息自动传递方式不可用。这是因为对于多重继承而言,信息传递将通过两条不同的途径。为避免这种冲突,当基类是虚的,将禁止信息通过中间类自动传递给基类。

       这就要求显式地调用所需的基类构造函数:

SingingWaiter(参数列表):Worker(wk),Waiter(wk,p),Singer(wk,v) { }

上述格式对虚基类来说是合法的,对非虚基类来说是非法的。

 

哪个方法

对于多重继承,如果每个祖先都有一个Show函数,那么会导致函数调用的二义性

对于单继承,如果没有重新定义show,将调用最近祖先中的show定义。

 

有几种解决方法:

1使用作用域解析运算符来澄清编程者的意图;

2或是在多重继承的类中重新定义show方法,并指出要使用哪个show;

       这种递增的方法对于单继承来说是有效的;

       但是对于多重继承来说,还是有问题:

              SingingWaiter::Show

              {Singer::Show();Waiter::Show();} //这将显示姓名和ID两次。

       该如何解决呢?->使用模块化方法,而不是递增的方法;即提供一个只显示worker组件的方法,提供一个只显示waiter组件及singer组件的方法。

 

将所有数据组件都设置为保护的方法,而不是私有的,可以更严格地控制对数据的访问;

       如果数据组件的方法是保护的,则只能在继承层次结构中的类中使用它,在其他地方则不能使用。

 

MI小结

       MI会增加编程的复杂度。然而,这种复杂度主要是由于派生类通过多条途径继承同一个基类引起的。

       当派生类使用关键字virtual来指示派生时,基类就称为了虚基类。其构造函数的规则有所变化,不会自动进行信息不换传递,需要显式地调用基类构造函数。

       通过优先规则解决名称二义性。如果一个类从两个不同的类那里继承了两个同名的成员,则需要在派生类中使用类限定符来区分它们。否则,编译器将指出二义性。

       有间接虚基类的派生类包含直接调用间接基类构造函数的构造函数,这对于间接非虚基类来说是非法的。

上一篇:利用Proxy.newProxyInstance实现AOP


下一篇:2021-05-14