我正在尝试了解对象内的虚拟指针放置,请澄清一下。我研究了两个不同的场景,即多态和多重继承。两者对于虚拟指针的位置都有不同的答案。
多态性
虚拟指针位于对象的顶部,并且仅用于该类,这意味着只有一个虚拟指针。例如:
class A {
public:
virtual void walk();
}
class B : A {
public:
int num;
virtual void walk();
virtual void run();
}
内存中的对象将如下所示:
| vPointer to class B vTable |
| int num |
多重继承
有多个虚拟指针,每个类一个。但是,此类的vTable已更改,因此覆盖的方法被定向到当前类的地址功能代码。但是,我认为这意味着每个类都可能具有多个不同的vTable。例如:
class A {
public:
virtual void walk();
}
class B {
public:
char name;
virtual void run();
}
class C : A, B {
public:
int num;
virtual void run();
virtual void walk();
virtual void swim();
}
内存中的对象将如下所示:
| vPointer to class A vTable |
| vPointer to class B vTable |
| char name |
| int num |
两者都正确吗?我四处搜寻,但只能找到关于多重继承的说明,而关于多态性却一无所获。
任何帮助将非常感激。
谢谢你。
该标准没有说明虚拟功能和多态性的实现(甚至没有提到vtables)。与派生类的内存布局无关,对象是内存区域并且包含基础子对象。
因此,我的回答不是关于C ++标准的一般说明,而只是关于实现通常如何行为的务实解释。
如果您对此类实现方面感兴趣,我强烈建议您这篇DDJ文章,该文章还解释了更复杂的情况,例如虚拟继承。
单继承多态
实际上,通过使用指向虚拟表的对象指针(由类的所有对象共享)来实现多态,其中包含指向虚拟函数的指针。此文章解释了很好的效果如何。
vtable指针存储在对象的开头,因为它是确保可以有效调用虚函数而不知道所指向对象的确切布局的最有效方法:
A a; B b; // example assumes that class B inherits A publicly
A *p = &b; // pointer to a base object for showing polymorphism in action
...
p->walk(); // at this stage, you don't know if p points to A or B.
// Bus as vtable pointer ist at the begin of the object, you don't have to care
因此,正如您所描述的那样。您始终可以通过查看由编译器生成的汇编代码来获得确认,以了解隐式构造函数如何将vtable加载到对象中。
具有多重继承的多态性
多重继承意味着您的派生对象C有两个子对象,一个用于A,一个用于B。每个子对象必须像其任何其他类型的对象一样管理其vtable。这意味着有两个vtable,每个vtable位于子对象的开头:
| vPointer to class A vTable |
| data for A object | => here it's empty
| vPointer to class B vTable |
| char name | => here the data for the b object
| int num |
这是必需的,因为您可以具有以下代码:
C c;
A *pa = &c; B *pb = &c;
pa->walk(); pb->run();
但是派生类C是它自己的类,并且还定义了一个虚函数:
C *pc = &c;
pc->walk(); pc->run(); pc->swim();
因此,这意味着D也有一个vtable。它存储在哪里?它必须在对象的开头。因此,C的vtable将是A的vtable的超集:
| vPointer to class C vTable | => the first functions in the table are those of A, followed by all the virtual functions of C.
| data for A object | => here it's empty
| vPointer to class B vTable |
| char name | => here the data for the b object
| int num |
这是MSVC2013为vtable生成的汇编程序:
CONST SEGMENT
??_7C@@6BB@@@ DD FLAT:??_R4C@@6BB@@@ ; C::`vftable' loaded at begin of B object
DD FLAT:?run@B@@UAEXXZ ; this is in fact the vtable for B
CONST ENDS
CONST SEGMENT
??_7C@@6BA@@@ DD FLAT:??_R4C@@6BA@@@ ; C::`vftable' loaded at begin of C object
DD FLAT:?walk@A@@UAEXXZ ; that's the subset for A
DD FLAT:?swim@C@@UAEXXZ ; that's the superset for C specific gunctions
CONST ENDS
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句