首先,我想清楚地表明我确实理解在C++标准中没有vtable和vptrs的概念.但是我认为几乎所有实现都以几乎相同的方式实现虚拟调度机制(如果我错了,请纠正我,但这不是主要问题).另外,我相信我知道虚函数是如何工作的,也就是说,我总能告诉我将调用哪个函数,我只需要实现细节.
假设有人问我以下内容:
"您的基类B具有虚函数v1,v2,v3和派生类D:B,它会覆盖函数v1和v3并添加虚函数v4.解释虚拟调度的工作原理".
我会这样回答:
对于每个具有虚函数的类(在本例中为B和D),我们有一个单独的指向函数的数组,称为vtable.
B的vtable将包含
&B::v1
&B::v2
&B::v3
Run Code Online (Sandbox Code Playgroud)
D的vtable将包含
&D::v1
&B::v2
&D::v3
&D::v4
Run Code Online (Sandbox Code Playgroud)
现在B类包含一个成员指针vptr.D自然地继承它,因此也包含它.在BB的构造函数和析构函数中设置vptr指向B的vtable.在DD的构造函数和析构函数中,它指向D的vtable.
对多态类X的对象x上的虚函数f的任何调用都被解释为对x.vptr的调用[f在vtables中的位置]
问题是:
1.我在上述描述中有任何错误吗?
2.编译器如何知道f在vtable中的位置(请详细说明)
3.这是否意味着如果一个类有两个基数那么它有两个vpt?在这种情况下发生了什么?(尝试以与我相似的方式描述,尽可能详细地描述)
4.钻石层次结构中发生了什么,其中A位于顶部B,C位于中间,D位于底部?(A是B和C的虚拟基类)
提前致谢.
Tra*_*kel 35
1.我在上面的描述中有任何错误吗?
都好.:-)
2.编译器如何知道f在vtable中的位置
每个供应商都有自己的方法,但我总是把vtable视为成员函数签名到内存偏移的映射.所以编译器只维护这个列表.
这是否意味着如果一个班级有两个基地,那么它有两个vptrs?在这种情况下发生了什么?
通常,编译器组成一个新的 vtable,它包含按指定顺序附加在一起的虚拟碱基的所有vtable,以及虚拟碱基的vtable指针.它们遵循派生类的vtable函数.这是极其供应商特定的,但对于class D : B1, B2你通常会看到D._vptr[0] == B1._vptr.

该图像实际上是用于组成对象的成员字段,但vtable可以由编译器以完全相同的方式组成(据我所知).
4.钻石层次结构中发生了什么,A在顶部B,C在中间,D在底部?(A是B和C的虚拟基类)
简短的回答?绝对的地狱.你真的继承了这两个基地吗?只是其中之一?他们都不是?最终,使用了为该类组成vtable的相同技术,但是这样做是如何完成的,因为它应该如何完成并不是一成不变的.有解决的钻石层次问题的解释体面这里,但是,像极了这一点,这是很特定于供应商.
具体实现,但大多数只是源代码顺序 - 意味着它们出现在类中的顺序 - 从基类开始,然后从派生类添加新的虚函数.只要编译器具有确定性的方法,那么它想做的任何事情都可以.但是,在Windows上,要创建COM兼容的V-Tables,它必须按源顺序排列
(不确定)
| 归档时间: |
|
| 查看次数: |
7495 次 |
| 最近记录: |