探索多态和多态对象模型—单一继承&多重继承

  • Post author:
  • Post category:其他




1.什么是多态?

谈到多态,我们必须首先了解一下什么是虚函数。

虚函数:在类的成员函数前加virtual关键字,把这个成员函数称为虚函数。


多态需满足两个条件:

子类的虚函数须覆盖(重写)父类的虚函数;(协变例外)

当使用基类的指针或引用调用重写的虚函数时,指向基类对象就调用基类的虚函数,指向派生类的对象就调用派生类的虚函数。


注:多态只与对象有关,与类型无关。


扩充:

虚函数重写(覆盖):

当派生类中定义的虚函数和基类中定义的虚函数完全相同的时候,则称派生类中的虚函数重写了基类中的虚函数。


协变:

class A
{
public:
    virtual A* func()---virtual A& func()
    {
        return this;---return *this;
    }
};
class B
{
public:
    virtual B* func()---virtual B& func()
    {
        return this;---return *this;
    }
};



2.多态的对象模型



单一继承模型

typedef void(*FUNC) ();
class First
{
public:
    First()
        :_f(1){}
    virtual void f(){ cout << "First::f()" << endl; }
    virtual void f1(){ cout << "First::f1()" << endl; }
public:
    int _f;
};
class Second : public First
{
public:
    Second()
        :_s(2){}
    virtual void f(){ cout << "Second::f()" << endl; }
    virtual void f2(){ cout << "Second::f2()" << endl; }
    virtual void f3(){ cout << "Second::f3()" << endl; }
public:
    int _s;
};

void Print(int *Vfptr)
{
    cout << "虚表地址" << Vfptr << endl;
    for (int i = 0; Vfptr[i] != 0; ++i)
    {
        FUNC f = (FUNC)Vfptr[i];
        cout << "[" << i << "]" << endl;
        f();
    }
    cout << endl;
}
int main()
{
    First f;
    Second s;

    int *Vfptr1 = (int*)(*(int*)&f);
    int *Vfptr2 = (int*)(*(int*)&s);

    Print(Vfptr1);
    Print(Vfptr2);
    system("pause");
    return 0;
}

这里写图片描述

单一继承总结:

虚函数表一般放在最前面;

成员变量根据会根据继承关系按先后顺序排列;

当有虚函数覆盖时,派生类的虚函数会将虚函数表中的基类虚函数替换;

虚函数表最后一个为0/NULL。

多重继承模型:

这里写图片描述

class B1
{
public:
    B1()
    :_b1(1){}
    virtual void b(){ cout << "B1::b()" << endl; }
    virtual void b1(){ cout << "B1::b1()" << endl; }
public:
    int _b1;
};

class B2 
{
public:
    B2()
    :_b2(2){}
    virtual void b(){ cout << "B2::b()" << endl; }
    virtual void b2(){ cout << "B2::b2()" << endl; }
    virtual void b3(){ cout << "B2::b3()" << endl; }
    virtual void b4(){ cout << "B2::b4()" << endl; }
public:
    int _b2;

};

class D : public B1 , public B2
{
public:
    D()
    :_d(3){}
    virtual void b(){ cout << "D::b()" << endl; }
    virtual void b1(){ cout << "D::b1()" << endl; }
    virtual void b3(){ cout << "D::b3()" << endl; }
    virtual void b5(){ cout << "D::b5()" << endl; }
public:
    int _d;
};

typedef void(*FUNC) ();//函数指针

void Print(int *Vfptr)
{
    cout << "虚表地址" << Vfptr << endl;
    for (int i = 0; Vfptr[i] != 0; ++i)
    {
        FUNC f = (FUNC)Vfptr[i];
        cout << "[" << i << "]" << endl;
        f();
    }
    cout << endl;
}
int main()
{
    D d;
    int *Vfptr1 = (int*)(*(int*)&d);
//B2的虚函数表在B1虚函数表的下面,跳过B1虚函数才可以打印出B2的虚函数表
    int *Vfptr2 = (int*)(*((int*)&d+sizeof(B1)/4));
    Print(Vfptr1);
    Print(Vfptr2);
    system("pause");
    return 0;
}

D继承后B1,B2后,D类的实例化对象模型:

这里写图片描述

在VS2013下的运行结果(打印的虚函数表):

这里写图片描述

多重继承总结:

派生类会继承每个基类的虚函数表;

派生类的成员函数会放在第一个基类的虚函数表中;

成员变量的存储顺序是按照继承先后顺序存储;

派生类中有和基类中相同的虚函数,基类的虚表会被改变。



版权声明:本文为qq_39295755原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。