多重继承(multiple inheritance)是指从多个直接基类中产生派生类的能力。多重继承的派生类继承了所有父类的属性。
一、多重继承例子:
1 class Bear : public ZooAnimal {}; 2 class Panda: public Bear, public Endangered { /*...*/};
派生类对象包含有每个基类的子对象,如下图所示:在Panda对象中含有一个Bear部分(其中又含有一个ZooAnimal部分)、一个Endangered部分以及在Panda中声明的非静态数据成员。
图1:Panda对象的概念结构
二、我们来看下多重继承的派生类的构造函数:
与从一个基类派生一样,多重继承的派生类的构造函数也只能初始化它的直接基类:
1 //显示初始化所有基类 2 //注意:该函数将它的前两个参数name和onExhibit传递给Bear的构造函数,由Bear的构造函数负责初始化Panda的基类部分。当Bear的构造函数体(空的)执行结束以后,构建对象 的基类部分也就完成了。 3 //基类的构造顺序与派生列表中基类的出现顺序一致,所以应该是先初始化Bear,再初始化Endangered。由于ZooAnimal又是Bear的基类,所以首先初始化ZooAnimal.其次是Bear,接着是Endangered,最后是Panda. 4 Panda::Panda(std::string name ,bool onExhibit) 5 :Bear(name,onExhibit,"Panda"), 6 Endangered(Endangered::critical){}
另外如果一个类从多个基类中继承了相同的构造函数(形参列表完全相同),则程序会出现错误。解决办法是:这个派生类必须为该构造函数定义它自己的版本。
三、我们来看下多重继承派生类的析构函数:
1 //派生类的析构函数只负责清除派生类本身分配的资源,它的成员及基类都是自动销毁的。 2 //析构函数的调用顺序与构造函数刚好相反 3 ~Panda ~Endangered ~Bear ~ZooAnimal
四、类型转换与多个基类:
我们可以令某个可访问的基类的指针和引用直接指向一个派生类对象。例如一个ZooAnimal、Bear、Endangered类型的指针可以绑定到Panda对象上。
五、基于指针或引用类型的查找:
对象、指针和引用的静态类型决定了我们能够使用哪些成员。如果我们使用一个ZooAnimal指针,则只有定义在ZooAnimal中的操作是可以使用的。类似,一个Bear指针或引用只能访问Bear及ZooAnimal的成员,一个Endangered的指针或引用只能访问Endangered的成员。
虚函数是一个例外。
六、多重继承下的类作用域:
在只有一个基类的情况下,派生类的作用域嵌套在直接基类和间接基类的作用域中,查找过程沿着继承体系自底向上进行,直到找到所需的名字。派生类的名字将隐藏基类的同名成员。
在多重继承的情况下,相同的查找过程在所有直接基类中同时进行。如果名字在多个基类中都被找到,则对该名字的使用将具有二义性,此时不加前缀限定符直接使用该名字将引发二义性。
七、虚继承:
虚基类的目的是令某个类做出声明,承诺愿意共享它的基类。其中共享的基类子对象称为虚基类(virtual base class),在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含唯一一个共享的虚基类子对象。
举个例子:
必须在虚派生的真实需求出现之前就已经完成虚派生的操作。例如当我们定义Panda时才出现了对虚派生的需求。虚派生只会影响从指定了虚基类的派生类(Bear和Raccoon)中进一步派生类(Panda),它不会影响派生类本身(Bear和Raccoon)
八、使用虚基类:
不论基类是不是虚基类,派生类对象都能被可访问基类的指针或引用操作。
九、构造函数与虚继承:
虚基类总是先于非虚基类构造,与他们在继承体系中的次序和位置无关。