C++中多重继承与虚继承资料的整理 (二)

2014-11-24 00:59:32 · 作者: · 浏览: 13
os {...};
class iostream : public istream, public ostream {...};

假定通过多个派生路径继承名为X的成员,有下面三种可能性:
1)如果在每个路径中X表示同一虚基类成员,则没有二义性,因为共享该成员的单个实例;
2)如果在某个路径中X是虚基类的成员,而在另一路径中X是后代派生类的成员,也没有二义性——特定派生类实例的优先级高于共享虚基类实例。
3)如果沿每个继承路径X表示后代派生类的不同成员,则该成员的直接访问是二义性的。

例如:


[cpp]
#include
class B {
public:
void print() {
std::cout << "B"<< std::endl;
}
};
class D1: public virtual B {
};
class D2: public virtual B {
public:
void print() {
std::cout << "D2"<< std::endl;
}
};
class DD: public D1, public D2 {
};
int main () {
DD d;
d.print(); // ok: call D2::print

return 0;
}

#include
class B {
public:
void print() {
std::cout << "B"<< std::endl;
}
};
class D1: public virtual B {
};
class D2: public virtual B {
public:
void print() {
std::cout << "D2"<< std::endl;
}
};
class DD: public D1, public D2 {
};
int main () {
DD d;
d.print(); // ok: call D2::print

return 0;
}

特殊的初始化语义

通常,每个类只初始化自己的直接基类。在应用于虚基类的时候,这个初始化策略会失败。如果使用常规规则,就可能会多次初始化虚基类。类将沿着包含该虚基类的每个继承路径初始化。

为了解决这个重复初始化问题,从具有虚基类的类继承的类对初始化进行特殊处理。在虚派生中,由最低层派生类的构造函数初始化虚基类。

虽然由最低层派生类初始化虚基类,但是任何直接或间接继承虚基类的类一般也必须为该基类提供自己的初始化式。只要可以创建虚基类派生类类型的独立对象,该类就必须初始化自己的虚基类,这些初始化式只在创建中间类型的对象时使用。

例如,我们有四个类:ZooAnimal, Bear, Raccoon和Panda,它们之间构造一个继承层次:Bear和Raccoon继承ZooAnimal,Panda继承Bear和Raccoon。那么,它们的构造函数就形如:
Bear::Bear(std::string name, bool onExhibit): ZooAnimal(name,onExhibit, "Bear") {}
Raccoon::Raccoon(std::string name, bool onExhibit):ZooAnimal(name, onExhibit, "Raccoon") {}
Panda::Panda(std::string name, bool onExhibit): ZooAnimal(name,onExhibit, "Panda"), Bear(name, onExhibit), Raccoon(name, onExhibit){}

当创建Panda对象的时候,构造过程如下:
1)首先使用构造函数初始化列表中指定的初始化式构造ZooAnimal部分;
2)接下来,构造Bear部分(在派生列表中Bear在前)。忽略Bear初始化列表中用于ZooAnimal构造函数的初始化式;
3)然后,构造Raccoon部分,再次忽略ZooAnimal初始化式;
4)最后,构造Panda部分。

如果Panda构造函数不显式初始化ZooAnimal基类,就使用ZooAnimal默认构造函数;如果ZooAnimal没有默认构造函数,则代码出错。

无论虚基类出现在继承层次中的任何地方,总是在构造非虚基类之前构造虚基类。

例如,有下面的继承关系:
class Character { };
class BookCharater: public Character { };
class ToyAnimal { };
class TeddyBear: public BookCharacter, public Bear, public virtualToyAnimal { };

直观继承图为:

按声明次序检查直接基类,确定是否存在虚基类。上例中,首先检查BookCharacter的继承子树,然后检查Bear的继承子树,最后检查 ToyAnimal的继承子树。按从根类开始向下到最低层派生类的次序检查每个子树。在这里依次检查到ZooAnimal和ToyAnimal为虚基类。

TeddyBear的虚基类的构造次序是先ZooAnimal再ToyAnimal(检查到的顺序)。一旦构造了虚基类,就按声明次序调用非虚基类的构造函数:首先是BookCharacter,它导致调用Character构造函数,然后是Bear。在这里,由最低层派生类TeddyBear指定用于 ZooAnimal和ToyAnimal的初始化式。

当然,对于析构函数的调用顺序与构造函数相反。

示例代码如下:

[cpp]
#include
class Character {
public:
Character() {
std::cout << "Character Constructor" << std::endl;
}
~Character() {
std::cout << "Character Destructor" << std::endl;
}
};
class BookCharacter: public Character {
public:
BookCharacter() {
std::cout << "BookCharacter Constructor" << std::endl;
}
~BookCharacter() {
std::cout << "BookCharacter Destructor" << std::endl;
}
};
class ZooAnimal {
public:
ZooAnimal() {
std::cout << "ZooAnimal Constructor" << std::endl;
}
~ZooAnimal() {
std::cout << "ZooAnimal Destructor" << std::endl;
}
};
class Bear: public virtual ZooAnimal {
public:
Bear() {
std::cout << "Bear Constructor" << std::endl;
}
~Bear() {
std::cout << "Bear Destructor" << std::endl;
}
};
class ToyAnimal {
public:
ToyAnimal() {
std::cout << "ToyAnimal Constructor" << std::endl;
}
~ToyAnimal() {
std::cout << "ToyAnimal Destructor" << std::endl;
}
};

class TeddyBear: public BookCharacter, public Bear, public virtual ToyAnimal {
public:
TeddyBear() {
std::cout << "TeddyBear Constructor" << std::endl;
}
~TeddyBear() {
std::cout << "TeddyBear Destructor" << std::endl;
}
};
int main () {
T