探究多态&虚表

多态


所谓多态,就是当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数。
下面来通过代码来理解多态的含义

class AA
{
public:
    virtual void fun()
    {
        cout << "AA::fun()" << endl;
    }
};

class BB : public AA
{
public:
    virtual void fun()
    {
        cout << "BB::fun()" << endl;
    }
};

void FUN(AA& a)
{
    a.fun();
}

void Test1()
{
    AA a;
    BB b;
    FUN(a);
    FUN(b);
}

结果为:
AA::fun()
BB::fun()
C++的多态分为静态多态动态多态
静态多态:静态多态就是重载,因为是在编译期决议确定。也就是在编译的时候就能确定函数的地址。
动态多态:是通过继承重写基类的虚函数实现的多态,在运行期间决议确定。也就是编译期间不知道函数的地址,只知道存储函数地址的虚表的地址。
C++中多态的实现就是通过虚函数实现的,虚函数的对象实例中都存在一张虚函数表。

虚函数表

虚函数表是通过一块连续内存来存储虚函数的地址,指明了实际调用的虚函数指针。

class AA
{
public:
    virtual void fun1()
    {}
    virtual void fun2()
    {}
protected:
    int _a;
};
void Test2()
{
    AA a;
}

这里写图片描述
通过监视窗口可以看到,对象a的首部存储了一个地址,指向的空间存储了虚函数的地址,称为虚函数表。所以sizeof(a)的值为8。

【含有虚函数的单继承对象模型】

typedef void(*FUNC) ();

class AA
{
public:
    virtual void fun1()
    {
        cout << "AA::fun1()" << endl;
    }
    virtual void fun2()
    {
        cout << "AA::fun2()" << endl;
    }
protected:
    int _a;
};

class BB : public AA
{
public:
    virtual void fun1()
    {
        cout << "BB::fun1()" << endl;
    }
    virtual void fun3()
    {
        cout << "BB::fun3()" << endl;
    }
protected:
    int _b;
};

void PrintfVTable(int *VTable)
{
    cout << "虚表地址:" << "0x" << VTable << endl;
    for (int i = 0; VTable[i] != 0; ++i)
    {
        cout <<"虚函数地址:0x"<< VTable[i] << " ";
        FUNC f = (FUNC)VTable[i];
        f();
    }
    cout << endl;
}

void Test3()
{
    AA a;
    BB b;
    int* VTable1 = (int *)(*(int *)&a);
    int* VTable2 = (int *)(*(int *)&b);
    PrintfVTable(VTable1);
    PrintfVTable(VTable2);
}

通过这种方式,可以依次打印出虚表地址以及虚函数的地址,结果如下:
这里写图片描述
这里写图片描述
虚表后面的0标志着虚表结束,类似于字符串结束符“/0”。

提示:若在windows平台vs下,程序出现异常中断,可以“清理解决方案”,这是由于编译器的小bug,没有在虚表最后加上0,出现死循环。

【含有虚函数的多继承对象模型】

typedef void(*FUNC) ();

class AA1
{
public:
    virtual void fun1()
    {
        cout << "AA1::fun1()" << endl;
    }
    virtual void fun2()
    {
        cout << "AA1::fun2()" << endl;
    }
protected:
    int _a1;
};

class AA2
{
public:
    virtual void fun1()
    {
        cout << "AA2::fun1()" << endl;
    }
    virtual void fun2()
    {
        cout << "AA2::fun2()" << endl;
    }
protected:
    int _a2;
};

class BB : public AA1,public AA2
{
public:
    virtual void fun1()
    {
        cout << "BB::fun1()" << endl;
    }
    virtual void fun3()
    {
        cout << "BB::fun3()" << endl;
    }
protected:
    int _b;
};
void PrintfVTable(int *VTable)
{
    cout << "虚表地址:" << "0x" << VTable << endl;
    for (int i = 0; VTable[i] != 0; ++i)
    {
        cout <<"虚函数地址:0x"<< VTable[i] << " ";
        FUNC f = (FUNC)VTable[i];
        f();
    }
    cout << endl;
}

void Test4()
{
    BB b;
    int* VTable = (int *)(*(int *)&b);
    PrintfVTable(VTable);

    VTable = (int *)(*((int*)&b + sizeof (AA1) / 4));
    PrintfVTable(VTable);
}

这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/it_10/article/details/55259551