cpp——类——VTBL

VTBL

VTBL,virtual table,即虚函数表,如果类包含virtual成员函数,就会生成VTBL,VTBL包含类的virtual成员函数入口地址,包含VTBL的类,其第一个字段为vptr指针,指向类的VTBL,因此VTBL被所有类实例对象所共享
子类会继承父类的VTBL,也会继承父类的vptr指针,并初始化为指向子类VTBL

单继承

继承父类VTBL

class CAnimal  
{  
public:  
    virtual void feed()  
    {  
        cout << "CAnimal::feed()" << endl;  
    }  
      
    virtual void work()  
    {  
        cout << "CAnimal::work()" << endl;  
    }  
};  
  
class CDog : public CAnimal  
{  
};  
  
typedef void (*PVM)();  
  
void vtbl()  
{  
    CAnimal animal;  
    cout << "sizeof(animal) = " << sizeof(animal) << endl;  
    cout << "animal vptr addr = " << (int*)&animal << endl;  
    cout << "animal vtbl addr = " << (int*)*(int*)&animal << endl;  
    cout << "animal feed addr = " << (int*)*((int*)*(int*)&animal) << endl;  
    cout << "animal work addr = " << (int*)*((int*)*(int*)&animal + 1) << endl;  
    PVM animal_vm1 = (PVM)(int*)*(int*)*(int*)&animal;  
    PVM animal_vm2 = (PVM)(int*)*((int*)*(int*)&animal + 1);  
    animal_vm1();  
    animal_vm2();  
      
    CDog dog;  
    cout << "sizeof(dog) = " << sizeof(dog) << endl;  
    cout << "dog vptr addr = " << (int*)&dog << endl;  
    cout << "dog vtbl addr = " << (int*)*(int*)&dog << endl;  
    cout << "dog feed addr = " << (int*)*((int*)*(int*)&dog) << endl;  
    cout << "dog work addr = " << (int*)*((int*)*(int*)&dog + 1) << endl;  
    PVM dog_vm1 = (PVM)(int*)*(int*)*(int*)&dog;  
    PVM dog_vm2 = (PVM)(int*)*((int*)*(int*)&dog + 1);  
    dog_vm1();  
    dog_vm2();  
}
output:
sizeof(animal) = 4
animal vptr addr = 003AFD54
animal vtbl addr = 0085DC74
animal feed addr = 00851032
animal work addr = 0085105A
CAnimal::feed()
CAnimal::work()
sizeof(dog) = 4
dog vptr addr = 003AFD30
dog vtbl addr = 0085DCAC
dog feed addr = 00851032
dog work addr = 0085105A
CAnimal::feed()
CAnimal::work()
总结:
  • 按virtual成员函数定义顺序依次把virtual成员函数入口地址加入VTBL
  • 子类继承父类VTBL

更新父类VTBL

class CAnimal
{
public:
    virtual void feed()
    {
        cout << "CAnimal::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CAnimal::work()" << endl;
    }
};

class CDog : public CAnimal
{
public:
    virtual void watch()
    {
        cout << "CDog::watch()" << endl;
    }
    
    virtual void work()
    {
        cout << "CDog::work()" << endl;
    }
};

typedef void (*PVM)();

void vtbl()
{
    CAnimal animal;
    cout << "sizeof(animal) = " << sizeof(animal) << endl;
    cout << "animal vptr addr = " << (int*)&animal << endl;
    cout << "animal vtbl addr = " << (int*)*(int*)&animal << endl;
    cout << "animal feed addr = " << (int*)*((int*)*(int*)&animal) << endl;
    cout << "animal work addr = " << (int*)*((int*)*(int*)&animal + 1) << endl;
    PVM animal_vm1 = (PVM)(int*)*(int*)*(int*)&animal;
    PVM animal_vm2 = (PVM)(int*)*((int*)*(int*)&animal + 1);
    animal_vm1();
    animal_vm2();
    
    CDog dog;
    cout << "sizeof(dog) = " << sizeof(dog) << endl;
    cout << "dog vptr addr = " << (int*)&dog << endl;
    cout << "dog vtbl addr = " << (int*)*(int*)&dog << endl;
    cout << "dog feed addr = " << (int*)*((int*)*(int*)&dog) << endl;
    cout << "dog work addr = " << (int*)*((int*)*(int*)&dog + 1) << endl;
    cout << "dog watch addr = " << (int*)*((int*)*(int*)&dog + 2) << endl;
    PVM dog_vm1 = (PVM)(int*)*(int*)*(int*)&dog;
    PVM dog_vm2 = (PVM)(int*)*((int*)*(int*)&dog + 1);
    PVM dog_vm3 = (PVM)(int*)*((int*)*(int*)&dog + 2);
    dog_vm1();
    dog_vm2();
    dog_vm3();
}
output:
sizeof(animal) = 4
animal vptr addr = 0028F9DC
animal vtbl addr = 00E1DC74
animal feed addr = 00E11032
animal work addr = 00E1105A
CAnimal::feed()
CAnimal::work()
sizeof(dog) = 4
dog vptr addr = 0028F9B8
dog vtbl addr = 00E1DCAC
dog feed addr = 00E11032
dog work addr = 00E114B5
dog watch addr = 00E114BA
CAnimal::feed()
CDog::work()
CDog::watch()
总结:
  • 按virtual成员函数定义顺序依次更新VTBL,若virtual成员函数已在VTBL中,用子类virtual成员函数入口地址更新之,若virtual成员函数不在VTBL中,添加到VTBL末尾

多重继承

继承父类VTBL

class CAnimal
{
public:
    virtual void feed()
    {
        cout << "CAnimal::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CAnimal::work()" << endl;
    }
};

class CDonkey : public CAnimal
{
public:
    virtual void feed()
    {
        cout << "CDonkey::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CDonkey::work()" << endl;
    }
    
    virtual void load()
    {
        cout << "CDonkey::load()" << endl;
    }
};

class CHorse: public CAnimal
{
public:
    virtual void feed()
    {
        cout << "CHorse::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CHorse::work()" << endl;
    }
    
    virtual void ride()
    {
        cout << "CHorse::ride()" << endl;
    }
};

class CMule : public CDonkey, public CHorse
{
};

typedef void (*PVM)();

void vtbl()
{
    CDonkey donkey;
    cout << "sizeof(donkey) = " << sizeof(donkey) << endl;
    cout << "donkey vptr addr = " << (int*)&donkey << endl;
    cout << "donkey vtbl addr = " << (int*)*(int*)&donkey << endl;
    cout << "donkey feed addr = " << (int*)*((int*)*(int*)&donkey) << endl;
    cout << "donkey work addr = " << (int*)*((int*)*(int*)&donkey + 1) << endl;
    cout << "donkey load addr = " << (int*)*((int*)*(int*)&donkey + 2) << endl;
    PVM donkey_vm1 = (PVM)(int*)*(int*)*(int*)&donkey;
    PVM donkey_vm2 = (PVM)(int*)*((int*)*(int*)&donkey + 1);
    PVM donkey_vm3 = (PVM)(int*)*((int*)*(int*)&donkey + 2);
    donkey_vm1();
    donkey_vm2();
    donkey_vm3();
    
    CHorse horse;
    cout << "sizeof(horse) = " << sizeof(horse) << endl;
    cout << "horse vptr addr = " << (int*)&horse << endl;
    cout << "horse vtbl addr = " << (int*)*(int*)&horse << endl;
    cout << "horse feed addr = " << (int*)*((int*)*(int*)&horse) << endl;
    cout << "horse work addr = " << (int*)*((int*)*(int*)&horse + 1) << endl;
    cout << "horse ride addr = " << (int*)*((int*)*(int*)&horse + 2) << endl;
    PVM horse_vm1 = (PVM)(int*)*(int*)*(int*)&horse;
    PVM horse_vm2 = (PVM)(int*)*((int*)*(int*)&horse + 1);
    PVM horse_vm3 = (PVM)(int*)*((int*)*(int*)&horse + 2);
    horse_vm1();
    horse_vm2();
    horse_vm3();
    
    CMule mule;
    cout << "sizeof(mule) = " << sizeof(mule) << endl;
    cout << "mule donkey vptr addr = " << (int*)&mule << endl;
    cout << "mule donkey vtbl addr = " << (int*)*(int*)&mule << endl;
    cout << "mule donkey feed addr = " << (int*)*((int*)*(int*)&mule) << endl;
    cout << "mule donkey work addr = " << (int*)*((int*)*(int*)&mule + 1) << endl;
    cout << "mule donkey load addr = " << (int*)*((int*)*(int*)&mule + 2) << endl;
    PVM mule_donkey_vm1 = (PVM)(int*)*(int*)*(int*)&mule;
    PVM mule_donkey_vm2 = (PVM)(int*)*((int*)*(int*)&mule + 1);
    PVM mule_donkey_vm3 = (PVM)(int*)*((int*)*(int*)&mule + 2);
    mule_donkey_vm1();
    mule_donkey_vm2();
    mule_donkey_vm3();
    cout << "mule horse vptr addr = " << (int*)&mule + 1 << endl;
    cout << "mule horse vtbl addr = " << (int*)*((int*)&mule + 1) << endl;
    cout << "mule horse feed addr = " << (int*)*((int*)*((int*)&mule + 1)) << endl;
    cout << "mule horse work addr = " << (int*)*((int*)*((int*)&mule + 1) + 1) << endl;
    cout << "mule horse ride addr = " << (int*)*((int*)*((int*)&mule + 1) + 2) << endl;
    PVM mule_horse_vm1 = (PVM)(int*)*((int*)*((int*)&mule + 1));
    PVM mule_horse_vm2 = (PVM)(int*)*((int*)*((int*)&mule + 1) + 1);
    PVM mule_horse_vm3 = (PVM)(int*)*((int*)*((int*)&mule + 1) + 2);
    mule_horse_vm1();
    mule_horse_vm2();
    mule_horse_vm3();
}
output:
sizeof(donkey) = 4
donkey vptr addr = 003AF874
donkey vtbl addr = 00D7DCAC
donkey feed addr = 00D714C9
donkey work addr = 00D714C4
donkey load addr = 00D714D3
CDonkey::feed()
CDonkey::work()
CDonkey::load()
sizeof(horse) = 4
horse vptr addr = 003AF844
horse vtbl addr = 00D7DD04
horse feed addr = 00D714BF
horse work addr = 00D714E2
horse ride addr = 00D714CE
CHorse::feed()
CHorse::work()
CHorse::ride()
sizeof(mule) = 8
mule donkey vptr addr = 003AF810
mule donkey vtbl addr = 00D7DD5C
mule donkey feed addr = 00D714C9
mule donkey work addr = 00D714C4
mule donkey load addr = 00D714D3
CDonkey::feed()
CDonkey::work()
CDonkey::load()
mule horse vptr addr = 003AF814
mule horse vtbl addr = 00D7DD70
mule horse feed addr = 00D714BF
mule horse work addr = 00D714E2
mule horse ride addr = 00D714CE
CHorse::feed()
CHorse::work()
CHorse::ride()
总结:
  • 多重继承类会继承各个父类VTBL和vptr(如果父类包含VTBL和vptr)
  • 多重继承类vptr顺序与子类继承父类顺序一致

更新父类VTBL

class CAnimal
{
public:
    virtual void feed()
    {
        cout << "CAnimal::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CAnimal::work()" << endl;
    }
};

class CDonkey : public CAnimal
{
public:
    virtual void feed()
    {
        cout << "CDonkey::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CDonkey::work()" << endl;
    }
    
    virtual void load()
    {
        cout << "CDonkey::load()" << endl;
    }
};

class CHorse: public CAnimal
{
public:
    virtual void feed()
    {
        cout << "CHorse::feed()" << endl;
    }
    
    virtual void work()
    {
        cout << "CHorse::work()" << endl;
    }
    
    virtual void ride()
    {
        cout << "CHorse::ride()" << endl;
    }
};

class CMule : public CDonkey, public CHorse
{
public:
    virtual void overload()
    {
        cout << "CMule::overload()" << endl;
    }
    
    virtual void work()
    {
        cout << "CMule::work()" << endl;
    }
    
    virtual void ride()
    {
        cout << "CMule::ride()" << endl;
    }
    
    virtual void load()
    {
        cout << "CMule::load()" << endl;
    }
};

typedef void (*PVM)();

void vtbl()
{
    CDonkey donkey;
    cout << "sizeof(donkey) = " << sizeof(donkey) << endl;
    cout << "donkey vptr addr = " << (int*)&donkey << endl;
    cout << "donkey vtbl addr = " << (int*)*(int*)&donkey << endl;
    cout << "donkey feed addr = " << (int*)*((int*)*(int*)&donkey) << endl;
    cout << "donkey work addr = " << (int*)*((int*)*(int*)&donkey + 1) << endl;
    cout << "donkey load addr = " << (int*)*((int*)*(int*)&donkey + 2) << endl;
    PVM donkey_vm1 = (PVM)(int*)*(int*)*(int*)&donkey;
    PVM donkey_vm2 = (PVM)(int*)*((int*)*(int*)&donkey + 1);
    PVM donkey_vm3 = (PVM)(int*)*((int*)*(int*)&donkey + 2);
    donkey_vm1();
    donkey_vm2();
    donkey_vm3();
    
    CHorse horse;
    cout << "sizeof(horse) = " << sizeof(horse) << endl;
    cout << "horse vptr addr = " << (int*)&horse << endl;
    cout << "horse vtbl addr = " << (int*)*(int*)&horse << endl;
    cout << "horse feed addr = " << (int*)*((int*)*(int*)&horse) << endl;
    cout << "horse work addr = " << (int*)*((int*)*(int*)&horse + 1) << endl;
    cout << "horse ride addr = " << (int*)*((int*)*(int*)&horse + 2) << endl;
    PVM horse_vm1 = (PVM)(int*)*(int*)*(int*)&horse;
    PVM horse_vm2 = (PVM)(int*)*((int*)*(int*)&horse + 1);
    PVM horse_vm3 = (PVM)(int*)*((int*)*(int*)&horse + 2);
    horse_vm1();
    horse_vm2();
    horse_vm3();
    
    CMule mule;
    cout << "sizeof(mule) = " << sizeof(mule) << endl;
    cout << "mule donkey vptr addr = " << (int*)&mule << endl;
    cout << "mule donkey vtbl addr = " << (int*)*(int*)&mule << endl;
    cout << "mule donkey feed addr = " << (int*)*((int*)*(int*)&mule) << endl;
    cout << "mule donkey work addr = " << (int*)*((int*)*(int*)&mule + 1) << endl;
    cout << "mule donkey load addr = " << (int*)*((int*)*(int*)&mule + 2) << endl;
    cout << "mule donkey overload addr = " << (int*)*((int*)*(int*)&mule + 3) << endl;
    cout << "mule donkey unkonwn addr = " << (int*)*((int*)*(int*)&mule + 4) << endl;
    PVM mule_donkey_vm1 = (PVM)(int*)*(int*)*(int*)&mule;
    PVM mule_donkey_vm2 = (PVM)(int*)*((int*)*(int*)&mule + 1);
    PVM mule_donkey_vm3 = (PVM)(int*)*((int*)*(int*)&mule + 2);
    PVM mule_donkey_vm4 = (PVM)(int*)*((int*)*(int*)&mule + 3);
    mule_donkey_vm1();
    mule_donkey_vm2();
    mule_donkey_vm3();
    mule_donkey_vm4();
    cout << "mule horse vptr addr = " << (int*)&mule + 1 << endl;
    cout << "mule horse vtbl addr = " << (int*)*((int*)&mule + 1) << endl;
    cout << "mule horse feed addr = " << (int*)*((int*)*((int*)&mule + 1)) << endl;
    cout << "mule horse work addr = " << (int*)*((int*)*((int*)&mule + 1) + 1) << endl;
    cout << "mule horse ride addr = " << (int*)*((int*)*((int*)&mule + 1) + 2) << endl;
    cout << "mule horse unkownd addr = " << (int*)*((int*)*((int*)&mule + 1) + 3) << endl;
    PVM mule_horse_vm1 = (PVM)(int*)*((int*)*((int*)&mule + 1));
    PVM mule_horse_vm2 = (PVM)(int*)*((int*)*((int*)&mule + 1) + 1);
    PVM mule_horse_vm3 = (PVM)(int*)*((int*)*((int*)&mule + 1) + 2);
    mule_horse_vm1();
    mule_horse_vm2();
    mule_horse_vm3();
}
output:
sizeof(donkey) = 4
donkey vptr addr = 004BFBF8
donkey vtbl addr = 0024DCAC
donkey feed addr = 002411F9
donkey work addr = 00241104
donkey load addr = 0024124E
CDonkey::feed()
CDonkey::work()
CDonkey::load()
sizeof(horse) = 4
horse vptr addr = 004BFBC8
horse vtbl addr = 0024DCFC
horse feed addr = 0024103C
horse work addr = 002413ED
horse ride addr = 0024121C
CHorse::feed()
CHorse::work()
CHorse::ride()
sizeof(mule) = 8
mule donkey vptr addr = 004BFB94
mule donkey vtbl addr = 0024DD4C
mule donkey feed addr = 002411F9
mule donkey work addr = 002410C3
mule donkey load addr = 00241352
mule donkey overload addr = 0024136B
mule donkey unkonwn addr = 00000000
CDonkey::feed()
CMule::work()
CMule::load()
CMule::overload()
mule horse vptr addr = 004BFB98
mule horse vtbl addr = 0024DD64
mule horse feed addr = 0024103C
mule horse work addr = 0024125D
mule horse ride addr = 00241014
mule horse unkownd addr = 00000000
CHorse::feed()
CMule::work()
CMule::ride()
总结:
  • 按virtual成员函数定义顺序依次并行更新VTBL,若virtual成员函数已在VTBL中,用子类virtual成员函数入口地址更新对应VTBL,若virtual成员函数不在所有VTBL中,只添加到第一张VTBL末尾,即按子类继承父类顺序第一个包含VTBL的父类VTBL中

你可能感兴趣的:(cpp)