在多重继承中,被重写的虚方法保存在c++的虚表中
where is the overridden virtual method saved in the vtable c++ in multiple inheritance
在c++中,在运行时没有类表示,但我总是可以在派生类中调用重写的虚方法。在虚表中保存的重写方法在哪里?下面是一段代码来演示:
struct B1 {
virtual void f() { ... }
};
struct B2 {
virtual void f() { ... }
virtual void g() { ... }
};
struct D : B1, B2 {
void f() { ... }
virtual void h() { ... }
};
D类对象的内存布局是什么?B1::f和B2::f保存在内存布局中(如果它们被保存的话)?
类D
的对象d
将只有一个指向类D
的VMT的指针,该指针将包含指向D::f的指针。因为B1:f和B2::f只能从D类的作用域中静态调用,所以对象d
不需要保持指向那些被覆盖的方法的动态指针。
这当然没有在标准中定义,这只是编译器通常的/逻辑实现。
实际上情况更复杂,因为D类的VMT合并了B1和B2类的VMT。但是,无论如何,在创建类B1的对象之前,不需要动态调用B1::f。
当编译器使用虚分派的虚表方法*时,被覆盖的成员函数的地址存储在定义该函数的基类的虚表中。
每个类都可以访问其所有基类的变量。这些变量存储在类本身的内存布局之外。每个具有虚成员函数的类,无论是声明的还是继承的,都有一个指向自己虚函数表的指针。调用重写的成员函数时,需要提供希望调用其成员函数的基类的名称。编译器知道所有类的虚表,因此它知道如何定位基类的虚表,在编译时进行查找,并直接调用成员函数。
下面是一个简短的例子:
struct A {
virtual void foo() { cout << "A"; }
};
struct B : public A { }; // No overrides
struct C : public B {
virtual void foo() { cout << "C"; }
void bar() { B::foo(); }
};
演示。
在上面的例子中,编译器需要查找B::foo
,它没有在B
类中定义。编译器查阅其符号表,发现B::foo
在A
中实现,并在C::bar
中生成对A::foo
的调用。
* vtables并不是实现虚拟调度的唯一方法。c++标准不要求使用变量表
尽管c++标准中没有强制要求,但每个已知的c++实现都使用相同的方法:每个至少具有虚函数的类都有一个vptr(指向虚函数表的指针)。
你没有提到虚拟继承,这是一种不同的、更微妙的继承关系;非虚继承是基类子对象和派生类之间的简单独占关系。
这里假设我们从至少具有虚函数的类派生。
在单继承的情况下,重用基类中的 vptr 。(不重用它只会浪费空间和运行时间。)基类称为"主基类"。
在多重继承的情况下,派生类的布局包含每个基类的布局,就像C语言中结构体的布局包含每个成员的布局一样。D
的布局是B1
然后B2
(实际上是任意顺序,但源代码通常保持顺序)。
第一个类是主基类:在D
中,从B1
指向D
的完整虚函数表,该虚函数表包含D
的所有虚函数。来自非主基类的每个vptr都指向D
的辅助虚函数表:该虚函数表仅包含来自该辅助基类的虚函数。
D
的构造函数必须初始化类实例的每个vptr,使其指向D
的适当虚函数表。
- C++模板来检查友元函数的存在
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 既然存在危险,为什么项目要使用-I include开关
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 我们可以访问一个不存在的联盟的成员吗
- C++:对不存在的命名空间使用命名空间指令
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- C++quit()函数中可能存在作用域问题
- C++擦除(如果存在)
- 在C++中将类(带有Vector成员)保存为二进制文件
- 使用导入的图像保存在 QT 中的 QLabel 中,保存 GUI 的状态
- 阵列不能两次将相同的名称保存,当要添加新字符串时,程序应检查以查看该名称是否已经存在
- 方法,该方法调用所有基类的同名方法(如果存在),并将返回值保存到列表中
- 什么设计模式将数据部分保存在持久存储 (SQL) 中,部分保存在 RAM(内存)中
- 是否存在可用于保存任何枚举值的整型?
- 将对象指针保存在 STL 容器中是否比将对象本身保存更好
- 从控制台保存信息,然后重新打开时,信息仍然存在