C++——多态之虚表

多态定义:多种形式或形态
多态分类
C++——多态之虚表_第1张图片
静态多态:在编译期间完成,编译器根据函数实参的类型推断出要调用哪个函数。
在这里我们只说函数重载,泛型编程在后面再进行介绍。
函数重载的条件
(1)在同一作用域
(2)函数名相同,参数不同
(3)返回值可以不同
动态多态;在程序执行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
实现动态多态的条件
1.必须是虚函数
关于虚函数
使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类必须对其进行重写。
将基类的某一个成员函数定义为虚函数,在派生类中该函数始终保持虚函数的特
性。
只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。
重写也称覆盖,函数重写的条件
(1)不在同一作用域(分别在基类和派生类)
(2)函数原型相同(函数名相同,参数相同,返回值相同)
(3)基类函数必须有virtual关键字
(4)访问修饰符可以不同
2.通过基类类型的引用或者指针调用虚函数
虚表:
对于有虚函数的类,编译器都会维护一张虚表,对象的前4个字节就是指向虚表的指针。C++——多态之虚表_第2张图片
下面来看一个派生类将基类的虚函数重写的例子,分析一下基类和派生类各自的虚函数表

class Base
{
public:
    virtual void Funtest1()
    {
        cout << "Base::Funtest1()" << endl;
    }
     virtual void Funtest2()
    {
        cout << "Base::Funtest2()" << endl;
    }
     virtual void Funtest3()
     {
         cout << "Base::Funtest3()" << endl;
     }
};

class Derived :public Base
{
public:
    virtual void Funtest1()
    {
        cout << "Derived::Funtest1()" << endl;
    }
    virtual void Funtest4()
    {
        cout << "Derived::Funtest4()" << endl;
    }
    virtual void Funtest5()
    {
        cout << "Derived::Funtest5()" << endl;
    }
};
typedef void(*PVFT)();
void PrintVFTable(Base& b)
{
    PVFT* pvtf = (PVFT*)(*(int*)&b);
    while (*pvtf)
    {
        (*pvtf)();
        pvtf++;
    }
}
int main()
{
    Derived d;
    Base b;
    Base& b1 = b;  
    b1=d;
    PrintVFTable(b1);
    system("pause");
    return 0;
}

C++——多态之虚表_第3张图片
C++——多态之虚表_第4张图片
单继承派生类的虚函数表生成
1.先拷贝基类的虚函数表生成;
2.如果派生类重写了基类的某个虚函数,就用派生类重写后的虚函数替换相同偏移量位置的虚函数;
3.如果派生类有新增的虚函数,跟在基类的虚函数地址后面。

class B1
{
public:
    B1()
    {
        _b1 = 0;
    }
    virtual void fun1()
    {
        cout << "B1::fun1()" << endl;
    }
    virtual void fun2()
    {
        cout << "B1::fun2()" << endl;
    }
private:
    int _b1;
};

class B2
{
public:
    B2()
    {
        _b2 = 1;
    }
    virtual void fun3()
    {
        cout << "B2::fun3()" << endl;
    }
    virtual void fun4()
    {
        cout << "B2::fun4()" << endl;
    }
private:
    int _b2;
};

class D :public B1, public B2
{
public:
    D()
    {
        _d = 2;
    }
    virtual void fun1()
    {
        cout << "D::fun1()" << endl;
    }
    virtual void fun3()
    {
        cout << "D::fun3()" << endl;
    }
    virtual void fun5()
    {
        cout << "D::fun5()" << endl;
    }
private:
    int _d;
};

typedef void(*PVTF)();
void PrintVpt(B1& b1, const char* _table)
{
    cout << _table << endl;
    PVTF* pVtf = (PVTF*)(*(int*)&b1);
    while (*pVtf)
    {
        (*pVtf)();
        ++pVtf;
    }
    cout << endl;
}

void PrintVpt(B2& b2, const char* _table)
{
    cout << _table << endl;
    PVTF* pVtf = (PVTF*)(*(int*)&b2);
    while (*pVtf)
    {
        (*pVtf)();
        ++pVtf;
    }
    cout << endl;
}

void test()
{
    D d;
    B1& b1 = d;
    B2& b2 = d;
    PrintVpt(b1, "D-->B1 vpf:");
    PrintVpt(b2, "D-->B2 vpf:");
}
int main()
{
    test();
    system("pause");
    return 0;
}

多继承多态派生类对象模型
C++——多态之虚表_第5张图片
多继承派生类的虚函数表生成
C++——多态之虚表_第6张图片
多继承派生类虚函数的顺序
1.如果派生类对B1中虚函数重写,替换相同位置的虚函数;
2.如果派生类对B2中虚函数重写,替换相同位置的虚函数;
3.如果派生类有自己新增的函数,放在第一张虚表之后。
多态下的菱形虚拟继承

class B
{
public:
    B()
    {
         _b = 1;
    }
    virtual void fun1()
    {
        cout << "B::fun1()" << endl;
    }
    virtual void fun2()
    {
        cout << "B::fun2()" << endl;
    }
private:
    int _b;
};

class C1:virtual public B
{
public:
    C1()
    {
         _c1 = 2;
    }
    virtual void fun1()
    {
        cout << "C1::fun1()" << endl;
    }
    virtual void fun3()
    {
        cout << "C1::fun3()" << endl;
    }
private:
    int _c1;
};

class C2 :virtual public B
{
public:
    C2()
    {
         _c2 = 3;
    }
    virtual void fun4()
    {
        cout << "C2::fun4()" << endl;
    }

private:
    int _c2;
};
class D :public C1, public C2
{
public:
    D()
    {
        _d = 4;
    }
    virtual void fun1()
    {
        cout << "D::fun1()" << endl;
    }
    virtual void fun4()
    {
        cout << "D::fun4()" << endl;
    }
    virtual void fun5()
    {
        cout << "D::fun5()" << endl;
    }
private:
    int _d;
};

typedef void(*PVTF)();
void PrintVpt(void* p, const char* _table)
{
    cout << _table << endl;
    PVTF* pVtf = (PVTF*)(*(int*)p);
    while (*pVtf)
    {
        (*pVtf)();
        ++pVtf;
    }
    cout << endl;
}

void test()
{
    D d;
    B& b = d;
    PrintVpt(&b, "D-->B vpf:");
    C1& c1 = d;
    PrintVpt(&c1, "D-->C1 vpf:");
    C2& c2 = d;
    PrintVpt(&c2, "D-->C2 vpf:");
}
int main()
{
    test();
    system("pause");
    return 0;
}

菱形虚拟继承派生类的对象模型
C++——多态之虚表_第7张图片
派生类的虚表生成
C++——多态之虚表_第8张图片
成员函数的调用过程
1.是否为虚函数
2.若为虚函数,找虚表指针->虚函数地址->调用相应的虚函数;若为非虚函数,直接调用相应的函数。

你可能感兴趣的:(C++——多态之虚表)