虚拟基类在内部如何工作?编译器如何解析对基方法的调用?

How does virtual base class works internally ? How the call to base methods resolved by compiler?

本文关键字:何解析 编译器 方法 调用 在内部 基类 何工作 工作 虚拟      更新时间:2023-10-16

我了解虚函数,但我对虚拟基类及其内部工作方式感到困惑。有人可以帮忙吗?

class Base { };

Derived: virtual public Base { };

我确实知道有一个副本被传递给派生类。

  • 但是有人可以解释一下这在内部是如何工作的吗?
  • 它将如何与虚拟功能相似或不同?
  • 以及如何解决对基方法的调用?

  • 如果派生类具有虚拟基类和虚函数,会发生什么情况?

谢谢。

引入了虚拟基类,以消除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");
}

请注意,现在罗威纳犬和赫斯基犬实际上继承了狗类。我们的最终目标是避免创建重复的基类。此代码将产生,

black Dog created
Age 4 black Rotweiler created
Teeth 24 black Husky created
Teeth 24 Age 4 black MixBreed created

但这里要注意的另一件事是,Dog 对象是由派生最多的类创建的,该类是类 MixBreed(您可以看到调用 Dog(( 构造函数(。这是因为罗威纳犬和赫斯基实际上都继承了狗。当上面的代码编译时,派生最多的类(即 MixBreed(应该调用 Dog 构造函数来创建唯一的 Dog 对象,否则会导致错误。来自 Rotweiler 和 Husky 的 Dog 构造函数调用都被忽略了,因为 Dog 对象已经从 MixBreed 类创建。

  • 虚拟基类对象由编译器在一开始创建,以避免重复。
  • 派生最多的类现在负责创建虚拟基类对象
  • 如果您实例化罗威纳犬或赫斯基犬,它们将正常工作(它们将创建 Dog 对象(

要记住的另一个事实是,所有继承虚拟基类的类都有一个虚拟表,它们将通过指针指向同一个基类对象。因此,基类中的所有派生类都可以访问基类的行为。