C ++ virtual functions and virtual function table

I. Definition virtual function

Modified keyword virtual member function, the purpose is to achieve polymorphism

ps:

About polymorphic {separate interface from implementation, a pointer to the parent class instance of a subclass and member functions by calling the parent class pointer subclass, which would allow the parent pointer has a variety of forms, so called polymorphism]

II. Vtable

The address table is a table of a class virtual functions, and inheritance for solving the problem coverage

1 has virtual functions have vtable

2. All objects vtable belong to the class, then the class virtual function table by the virtual function table pointer of the shared classes

3. The role of the virtual function table: When using a parent class pointer to operate subclass object, like a virtual table, like the map indicating the actual function should be called

4.c ++ compiler guarantees vtable pointer exists in the foremost position object instance (in order to ensure the performance of the function table obtained in the case of multiple inheritance inheritance or multilayer), which means that we can address through an object instance to obtain the virtual function table, and then can traverse the virtual function pointer wherein, in response to the virtual function call and

ps: Multiple inheritance: a plurality of parent classes, the multilayer to inherit: there is the parent class parent class

01

[Virtual function table by traversing virtual function pointer, the virtual function call response]

#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
    virtual void f()
    {
        cout << "Base::f" << endl;
    }
    virtual void g()
    {
        cout << "Base::g" << endl;
    }
    virtual void h()
    {
        cout << "Base::h" << endl;
    }

};
typedef void (* Fun) ( void ); 
Base B; 
Fun pFun = NULL; 

int main () 
{ 
    COUT << " virtual function table address: " << ( int *) (& B) << endl; 
    COUT << " vtable - first address of a function: " << ( int *) * ( int *) (& B) << endl; 

    // virtual function is called by the virtual function table 
    pFun = (Fun) * (( int *) * ( int *) (& B));    // Base :: F () 
    pFun ();
    pFun =(Fun)*((int*)*(int*)(&b)+1);  // Base::g()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&b)+2);  // Base::h()
    pFun();
}
View Code

result:

Virtual function table address: 0x477008 
virtual function table - the first address of a function: 0x473668 
Base :: F 
Base G :: 
Base :: H
View Code

The above is no succession

1. single virtual function inherited without coverage

02

03

1) into the virtual function table in declaration order

2) the former parent class virtual function, virtual function in the subclass

3) the end of the end-point identifier number virtual function table, different values ​​at different compilers

#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
    virtual void f()
    {
        cout << "Base::f" << endl;
    }
    virtual void g()
    {
        cout << "Base::g" << endl;
    }
    virtual void h()
    {
        cout << "Base::h" << endl;
    }

};
class Base_son:public Base
{
public:
    virtual void f1()
    {
        cout << "Base_son::f1" << endl;
    }
    virtual void g1()
    {
        cout << "Base_son::g1" << endl;
    }
    virtual void h1()
    {
        cout << "Base_son::h1" << endl;
    }

};


typedef void(*Fun)(void);
Base_son d;

Fun pFun = NULL;

int main()
{
    cout << "虚函数表地址:" << (int*)(&d) << endl;
    cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&d) << endl;

    //通过虚函数表调用虚函数
    pFun = (Fun)*((int*)*(int*)(&d));   // Base::f()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+1);  // Base::g()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+2);  // Base::h()
    pFun();

    pFun =(Fun)*((int*)*(int*)(&d)+3);  // Base_son::f1()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+4);  // Base_son::g1()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+5);  // Base_son::h1()
    pFun();

    return 0;
}
View Code

结果:

虚函数表地址:0x477008
虚函数表 — 第一个函数地址:0x473668
Base::f
Base::g
Base::h
Base_son::f1
Base_son::g1
Base_son::h1
View Code

2.单层继承有虚函数覆盖的情况

04

05

1)覆盖的f()函数被放到了虚函数表中原父类虚函数的位置

2)没有被覆盖的函数没有变化

#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
    virtual void f()
    {
        cout << "Base::f" << endl;
    }
    virtual void g()
    {
        cout << "Base::g" << endl;
    }
    virtual void h()
    {
        cout << "Base::h" << endl;
    }

};
class Base_son:public Base
{
public:
    virtual void f()
    {
        cout << "Base_son::f" << endl;
    }
    virtual void g1()
    {
        cout << "Base_son::g1" << endl;
    }
    virtual void h1()
    {
        cout << "Base_son::h1" << endl;
    }

};


typedef void(*Fun)(void);
Base_son d;

Fun pFun = NULL;

int main()
{
    cout << "虚函数表地址:" << (int*)(&d) << endl;
    cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&d) << endl;

    //通过虚函数表调用虚函数
    pFun = (Fun)*((int*)*(int*)(&d));   // Base_son::f()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+1);  // Base::g()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+2);  // Base::h()
    pFun();

    pFun =(Fun)*((int*)*(int*)(&d)+3);  // Base_son::g1()
    pFun();
    pFun =(Fun)*((int*)*(int*)(&d)+4);  // Base_son::h1()
    pFun();

    return 0;
}
View Code

结果:

虚函数表地址:0x477008
虚函数表 — 第一个函数地址:0x473650
Base_son::f
Base::g
Base::h
Base_son::g1
Base_son::h1
View Code

通过父类指针指向子类实例,子类覆盖父类方法,然后调用子类的方法,这样就实现了多态

Base *b=new Base_son(); b->f();

3.多重继承无虚函数覆盖

06

07

1)每个父类都有自己的虚函数表

2)子类的虚函数被放到第一个父类的虚函数表中

这样做是为了解决不同的父类类型指针指向同一个子类实例,而能够调用到实际的函数

4.多重继承存在虚函数覆盖

08

09

1)父类虚函数表中被覆盖的虚函数全部被替换成了子类的覆盖虚函数

这样我们就通过父类指向子类从而访问子类的f()了

Derive d;
Base1 *b1 = &d;
Base2 *b2 = &d;
Base3 *b3 = &d;
b1->f(); //Derive::f()
b2->f(); //Derive::f()
b3->f(); //Derive::f()
 
b1->g(); //Base1::g()
b2->g(); //Base2::g()
b3->g(); //Base3::g()
View Code

使用虚函数表可以做一些违反c++语义的事情:

1)通过父类指针访问子类自己的虚函数

子类的虚函数X在父类中没有,所以子类的虚函数X没有覆盖父类的虚函数,但是如果我们通过父类的指针来访问子类自己的虚函数的编译器会报错

Base1 *b1 = new Derive();
b1->f1();  //编译出错

但是我们通过虚函数表可以做到这种违背C++语义的事情:使用父类指针访问子类自己的虚函数

2)访问父类non-public的虚函数

如果父类的虚函数是private或protected的,但是这些feipublic的父类虚函数同样会存在于虚函数表中,所以我们可以通过访问虚函数表访问到这些虚函数

附上多重继承有虚函数覆盖的样例代码:

#include <iostream>
using namespace std;
 
class Base1 {
public:
            virtual void f() { cout << "Base1::f" << endl; }
            virtual void g() { cout << "Base1::g" << endl; }
            virtual void h() { cout << "Base1::h" << endl; }
 
};
 
class Base2 {
public:
            virtual void f() { cout << "Base2::f" << endl; }
            virtual void g() { cout << "Base2::g" << endl; }
            virtual void h() { cout << "Base2::h" << endl; }
};
 
class Base3 {
public:
            virtual void f() { cout << "Base3::f" << endl; }
            virtual void g() { cout << "Base3::g" << endl; }
            virtual void h() { cout << "Base3::h" << endl; }
};
 
class Derive : public Base1, public Base2, public Base3 {
public:
            virtual void f() { cout << "Derive::f" << endl; }
            virtual void g1() { cout << "Derive::g1" << endl; }
};
 
typedef void(*Fun)(void);
 
int main()
{
            Fun pFun = NULL;
 
            Derive d;
            int** pVtab = (int**)&d;
 
            //Base1's vtable
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+0);
            pFun = (Fun)pVtab[0][0];
            pFun();
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+1);
            pFun = (Fun)pVtab[0][1];
            pFun();
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+2);
            pFun = (Fun)pVtab[0][2];
            pFun();
 
            //Derive's vtable
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+3);
            pFun = (Fun)pVtab[0][3];
            pFun();
 
            //The tail of the vtable
            pFun = (Fun)pVtab[0][4];
            cout<<pFun<<endl;
 
            //Base2's vtable
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
            pFun = (Fun)pVtab[1][0];
            pFun();
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
            pFun = (Fun)pVtab[1][1];
            pFun();
 
            pFun = (Fun)pVtab[1][2];
            pFun();
 
            //The tail of the vtable
            pFun = (Fun)pVtab[1][3];
            cout<<pFun<<endl;
 
            //Base3's vtable
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
            pFun = (Fun)pVtab[2][0];
            pFun();
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
            pFun = (Fun)pVtab[2][1];
            pFun();
 
            pFun = (Fun)pVtab[2][2];
            pFun();
 
            //The tail of the vtable
            pFun = (Fun)pVtab[2][3];
            cout<<pFun<<endl;
 
            return 0;
}
View Code

 

About virtual function and normal function:

1. The class virtual function is dynamically generated by the access point to the virtual function table memory is not allocated for the object class, no virtual function table, can not access the virtual function

2. Class ordinary function to generate a static, not allocate an object class may access

Reference: mouse left ear: C ++ virtual function table parsing

 

Guess you like

Origin www.cnblogs.com/yinbiao/p/10987640.html