Inheritance 与多重继承相比,如果对象具有多态性,则虚拟指针在对象中的位置是否不同?

Inheritance 与多重继承相比,如果对象具有多态性,则虚拟指针在对象中的位置是否不同?,inheritance,polymorphism,virtual,multiple-inheritance,vtable,Inheritance,Polymorphism,Virtual,Multiple Inheritance,Vtable,我试图了解虚拟指针在一个对象中的位置,并希望一些澄清请。我研究了两种不同的场景,即多态性和多重继承。对于虚拟指针的位置,两者都有不同的答案。 多态性 虚拟指针位于对象的顶部,并且仅适用于该类,这意味着只有一个虚拟指针。例如: class A { public: virtual void walk(); } class B : A { public: int num; virtual void walk(); v

我试图了解虚拟指针在一个对象中的位置,并希望一些澄清请。我研究了两种不同的场景,即多态性和多重继承。对于虚拟指针的位置,两者都有不同的答案。


多态性
虚拟指针位于对象的顶部,并且仅适用于该类,这意味着只有一个虚拟指针。例如:

class A {
    public:
        virtual void walk();
}

class B : A {
    public:
        int num;

        virtual void walk();
        virtual void run();
}
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 B vTable |
| int num                    |
| vPointer to class A vTable |
| vPointer to class B vTable |
| char name                  |
| int num                    |


多重继承
有多个虚拟指针,每个类一个。但是,此类的vTables会被更改,以便覆盖方法并定向到当前类函数代码的地址。然而,我认为这意味着每个类都可能有多个不同的vtable。 例如:

class A {
    public:
        virtual void walk();
}

class B : A {
    public:
        int num;

        virtual void walk();
        virtual void run();
}
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 B vTable |
| int num                    |
| vPointer to class A vTable |
| vPointer to class B vTable |
| char name                  |
| int num                    |
这两个或其中一个都正确吗?我四处搜索,但只能找到关于多重继承的说明,而没有关于多态性的说明

任何帮助都将不胜感激


谢谢。

该标准没有提到虚拟函数和多线程的实现(甚至没有提到vtables)。除了对象是内存区域并且包含基本子对象之外,派生类的内存布局也并没有任何内容

我的答案不是关于C++标准的一般性陈述,而是对实现一般行为的实用解释。p> 如果您对这些实现方面感兴趣,我强烈推荐您,这也解释了更复杂的情况,例如虚拟继承

单遗传多态性

多态性实际上是通过使用指向虚拟表(由类的所有对象共享)的对象指针实现的,该表包含指向虚拟函数的指针。这个很好地解释了它的工作原理

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为vtables生成的汇编程序:

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

C++语言规范不需要任何特定的虚拟调度实现。这取决于实现。