18.3 多重继承与虚继承
规则基本与“单继承”是一样的,在次记录几点需要关注的点!
派生类构造函数初始化所有基类
构造一个派生类的对象将同时初始化它的所有基类子对象。多重继承的派生类的构造函数初始值也只能初始化它的直接基类:
1 class ZooAnimal { }; 2 class Bear:public ZooAnimal { }; 3 class Endangered { }; 4 class Panda:public Bear,public Endangered {/*......*/}; 5 6 //显式地初始化所有基类 7 Panda::Panda(string name,bool onExhibit) 8 :Bear(name,onExhibit,"Panda"), 9 Endangered(Endangered::critical) { } 10 //隐式使用Bear的默认构造函数初始化Bear子对象(前提是:Bear类含有默认构造函数) 11 Panda::Panda() 12 :Endangered(Endagered::critical) { }
基类的构造顺序与派生列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关。
继承的构造函数与多重继承
多重继承问题1:如果从多个基类中继承了相同的构造函数(即形参列表完全相同),则程序将产生错误:
解决办法:这个类必须为该构造函数定义它自己的版本!
类型转换与多个基类
编译器不会在派生类向基类的几种转换中进行比较和选择,因为它认为转换到任意一种基类都一样好。
问题2:这时要注意二义性错误。
例如,存在以下所示的print重载版本:
void print(const Bear&); void print(const Endangered&); Panda ying_yang("ying_yang"); print(ying_yang); //二义性错误
注意二者缺一不可:
1.派生类向基类的类型转换存在;
2.转换可访问。
多重继承下的类作用域
派生类的作用域嵌套在直接基类和间接基类的作用域中。查找过程沿着体系自底向上进行。
问题3:当一个类拥有多个基类时,有可能出现派生类从两个或多个基类中继承了同名成员的情况。此时,不加前缀限定符直接使用该名字将引发二义性。
解决办法:1.不调用;2.限定符指定版本;3.定义一个新版本。
虚继承
在默认情况下,派生类中含有继承链上每个类对应的子部分。如果某个类在派生过程中出现了多次,则派生类中将包含该类的多个子对象。
问题4:这种默认情况对某些形如iostream的类是行不通的。一个iostream对象肯定希望在同一个缓冲区中进行读写操作,也会要求条件状态能同时反映输入输出操作的情况。假如在iostream对象中真的包含了base_ios的两份拷贝,则上述的共享行为就无法实现了。
解决办法:虚继承