虚拟基类在内部如何工作?编译器如何解析对基方法的调用?
How does virtual base class works internally ? How the call to base methods resolved by compiler?
我了解虚函数,但我对虚拟基类及其内部工作方式感到困惑。有人可以帮忙吗?
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 对象(
要记住的另一个事实是,所有继承虚拟基类的类都有一个虚拟表,它们将通过指针指向同一个基类对象。因此,基类中的所有派生类都可以访问基类的行为。
相关文章:
- 为什么编译器将其解析为函数指针而不是递归调用?
- 解析为 x3::variant 时出现编译器错误
- 虚拟基类在内部如何工作?编译器如何解析对基方法的调用?
- 跨编译器的 constexpr 成员函数的重载解析不一致
- 编译器差异:别名解析和名称查找之间的交互
- 编译器告诉我它无法解析重载函数的地址.对于 switch() 语句,这意味着什么
- "string_literal"解析为布尔值,但不解析为 std::string,当编译器选择函数的重载版本时
- 如果基类和派生类都具有相同的成员变量,编译器如何解析要调用的成员
- 编译器C++实例化之前解析模板?为什么
- 需要帮助为JNI调用构建DLL.未解析的外部引用.Borland编译器
- 在eclipse CDT GCC Builtin编译器上,处的std矢量无法解析
- 是否允许编译器在重载解析期间选择const-ref而不是ref
- 编译器是否会将这个表达式优化为一个临时常量,而不是每次迭代都解析它
- 使用模板调用重载函数(未解析的重载函数类型编译器错误)
- 提振.使用可选解析器的Qi编译器错误
- 应用范围解析运算符会导致编译器阻塞
- 为什么不能使用 LEX/YACC 来解析编译器的C++?
- 什么是浮点推测,它与编译器的浮点模型有何不同
- 我应该编写自己的数据结构来处理语义解析还是直接在编译器项目中使用STL
- 试图使用boost::spirit解析字符串中的整数时,编译器出现错误