已引入虚拟基类以消除在 C++ 中的多重继承中出现的菱形问题。例如,
#include <iostream>
#include <string>
using namespace std;
class Dog{
string color;
public:
Dog(string color): color(color)
{cout<<color<<" Dog created"<<endl;}
};
class Rotweiler: public Dog{
int age;
public:
Rotweiler(int age, string color): Dog(color), age(age)
{cout<<"Age "<<age<<" "<<color<<" Rotweiler created"<<endl;}
};
class Husky: public Dog{
int teeth;
public:
Husky(int teeth, string color): Dog(color), teeth (teeth)
{cout<<"Teeth "<<teeth<<" "<<color<<" Husky created"<<endl;}
};
class MixBreed: public Rotweiler, public Husky{
public:
MixBreed(int teeth, int age, string color): Rotweiler(age,color), Husky(teeth,color)
{cout<<"Teeth "<<teeth<<" Age "<<age<<" "<<color <<" MixBreed created"<<endl;}
};
int main(){
MixBreed puppy(24,4,"black");
}
此代码将导致,
black Dog created
Age 4 black Rotweiler created
black Dog created
Teeth 24 black Husky created
Teeth 24 Age 4 black MixBreed created
如您所见,我们打算创建一只狗和另外两只来自同一只狗的罗威纳犬和哈士奇犬,最后是从罗威纳犬和哈士奇犬衍生的混合品种。但是编译器创建了两个独立的 Dog 基类对象,而不是派生自同一个 Dog 对象。为了解决这个问题,我们可以使用虚拟继承。
#include <iostream>
#include <string>
using namespace std;
class Dog{
string color;
public:
Dog(string color): color(color)
{cout<<color<<" Dog created"<<endl;}
};
class Rotweiler: virtual public Dog{
int age;
public:
Rotweiler(int age, string color): Dog(color), age(age)
{cout<<"Age "<<age<<" "<<color<<" Rotweiler created"<<endl;}
};
class Husky: virtual public Dog{
int teeth;
public:
Husky(int teeth, string color): Dog(color), teeth (teeth)
{cout<<"Teeth "<<teeth<<" "<<color<<" Husky created"<<endl;}
};
class MixBreed: public Rotweiler, public Husky{
public:
MixBreed(int teeth, int age, string color): Dog(color), Rotweiler(age,color), Husky(teeth,color) // notice Dog constructor called here
{cout<<"Teeth "<<teeth<<" Age "<<age<<" "<<color <<" MixBreed created"<<endl;}
};
int main(){
MixBreed puppy(24,4,"black");
}
现在请注意,Rottweiler 和 Husky 实际上继承了 Dog 类。我们的最终目标是避免创建重复的基类。这段代码会产生,
black Dog created
Age 4 black Rotweiler created
Teeth 24 black Husky created
Teeth 24 Age 4 black MixBreed created
但这里要注意的另一件事是 Dog 对象是由最派生的类 MixBreed 创建的(您可以看到 Dog() 构造函数被调用)。这是因为罗威纳犬和哈士奇犬实际上都继承了 Dog。上述代码编译时,派生最多的类是 MixBreed 应该调用 Dog 构造函数来创建唯一的 Dog 对象,否则会导致错误。来自 Rotweiler 和 Husky 的 Dog 构造函数调用都被忽略,因为 Dog 对象已经从 MixBreed 类创建。
- 编译器一开始就创建了虚拟基类对象,以避免重复。
- 现在派生最多的类负责创建虚拟基类对象
- 如果您实例化 Rotweiler 或 Husky,它们将正常工作(它们将创建 Dog 对象)
另一个要记住的事实是所有继承一个虚拟基类的类都会有一个虚拟表,它们会通过一个指针指向同一个基类对象。因此基类的所有派生类都可以访问基类的行为。