深入理解虚函数

我们先来看一下没有继承的情况下有虚函数的对象的内存布局:
这里写图片描述

在对象的最开始处,是一个虚函数表指针,这个指针指向了一个虚函数表,表中的每一项都是一个虚函数的地址。接着来看看代码,如何不通过对象直接调用虚函数?甚至调用对象的私有函数。
直接上代码吧,详细解释看注释:

#include <iostream>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A: constructor"<<endl;
    }
private:
    void test()
    {
        cout<<"test"<<endl;
    }
    virtual void func1()
    {
        cout<<"base func1"<<endl;
    }
    virtual void func2()
    {
        cout<<"base func2"<<endl;
    }
    virtual void func3()
    {
        cout<<"base func3"<<endl;
    }
    virtual void func4()
    {
        cout<<"base func4"<<endl;
    }

};
int main() {
    A a;
    void *p = &a;
    typedef void(*Func)(void);
    cout << "a对象的地址为" << (void *) &a << endl;
    cout << "虚函数表的地址为" << hex << *((long *) &a) << endl;
    cout << "第一个虚函数的地址为" << hex << ((long *) *(long *) (&a)) << endl;
    Func pFunc1 = (Func) *(((long *) *(long *) (&a)));//调用第一个虚函数
    pFunc1();
    Func pFunc2 = (Func) *(((long *) *(long *) (&a))+1);//调用第二个虚函数
    pFunc2();
    Func pFunc3 = (Func) *(((long *) *(long *) (&a))+2);//调用第三个虚函数
    pFunc3();
//1.(long*)(&a)->得到虚函数表指针的位置
//2.*(long*)(&a)->得到虚函数表指针的内容-虚函数表的地址
//3.(long*)*(long*)(&a)->得到第一个虚函数的地址
//4.*((long*)*(long*)(&a))->得到第一个虚函数
//5.(Func)*((long*)*(long*)(&a))->强制转换为函数类型
}

执行结果:

这里写图片描述
这样我们就通过直接寻找虚函数地址而不经过对象直接调用了类的虚函数,并且调用了其私有的函数。

猜你喜欢

转载自blog.csdn.net/darmao/article/details/80003011
今日推荐