C++ 多态模型的剖析

一、多态的概念
所谓的多态性,就是不同的对象收到相同的消息时产生不同的动作,即同一个函数名下定义的不同功能的函数,这些函数执行不同但又有类似的操作,从而可以使用相同的方式来调用这些不同功能的同名函数,即“一个接口,多种方法”。

二、多态的分类
1.静态多态(重载函数 模板等):
编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式的类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

2.动态多态(虚函数等):
动态绑定:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的的方法。
动态绑定的条件(两个条件必须同时满足):
(1)必须是虚函数;
(2)通过基类的引用或指针调用函数。
使用virtual关键字修饰类的成员函数时,注明该函数时虚函数,派生类需要重新实现,编译器将实现动态绑定。

三、关于:函数重载、同名隐藏、重写举例
这里写图片描述
函数重载:

//函数重载
int add(int x, int y)
{
    return x + y;
}

double add(float x, float y)
{
    return x + y;
}

int main()
{
    int a = 1, b = 2;
    int ret1 = a + b;

    float c = 3.14f, d = 2.2f;
    float ret2 = c + d;
    cout <<"int: "<<ret1 << endl;
    cout << "double:  "<<ret2 << endl;

    system("pause");
    return 0;
}

这里写图片描述

重写:

class Base
{
public:
    virtual Base& fun(int x, int y)
    {
        a = x;
        b = y;
        cout << "Base::" << a << " " << b << endl;
        return *this;
    }

private:
    int a;
    int b;
};

class Derived:public Base
{
public:
    Derived& fun(int x, int y)
    {
        c = x + y;
        cout << "Derived::" << c << endl;
        return *this;
    }
private:
    int c;
};

int main()
{
    Base b;
    Derived d;

    b.fun(1, 2);
    d.Derived::fun(5, 6);
    system("pause");
    return 0;
}

这里写图片描述

同名隐藏:

//同名隐藏
class Base
{
public:
    int show()
    {
        cout << "Base::show()" << endl;
        return 0;
    }
};

class Derived :public Base
{
public:
    void show()
    {
        cout << "Derived::show()" << endl;
    }
};

int main()
{
    Derived d;

    d.show();
    d.Base::show();

    system ("pause");
    return 0;
}

这里写图片描述

四、虚表剖析
对于有虚函数的类(即抽象类),编译器都会维护一张虚表,对象的前四个字节存储的就是指向虚表的指针,虚表中按照虚函数在类中声明的顺序依次存放了各个虚函数的地址。

1.单继承中的模型

//没有覆盖且派生类没有添加虚函数
class B
{
public:
    virtual void Funtest1()
    {
        cout << "B::Funtest1" << endl;
    }

    virtual void Funtest2()
    {
        cout << "B::Funtest2" << endl;
    }

    virtual void Funtest3()
    {
        cout << "B::Funtest3" << endl;
    }

    virtual void Funtest4()
    {
        cout << "B::Funtest4" << endl;
    }
};

class D :public B
{};

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

void PrintVpf()
{
    D b;
    Vpf* fun = (Vpf*)*(int*)&b;

    while (*fun)
    {
        (*fun)();
        fun++;
    }
}

int main()
{
    cout << sizeof(B) << endl;
    cout << sizeof(D) << endl;
    PrintVpf();

    system("pause");
    return 0;
}

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

单继承继承规则:
1.如果派生类没有重写基类的虚函数,并且没有添加自己的虚函数,则直接继承基类的虚函数;
2.若派生类新增了虚函数,则虚表先存放基类继承来的虚函数,再存放派生类的虚函数,之后存放派生类自己的虚函数。
3.若基类中有虚函数被派生类重写,派生类中重写的虚函数会替换基类中被重写虚函数的位置,之后存放派生类新添加的虚函数。

2.多继承:

class B1
{
public:
    virtual void Funtest1()
    {
        cout << "B1::Funtest1" << endl;
    }
};

class B2
{
public:
    virtual void Funtest2()
    {
        cout << "B2::Funtest2" << endl;
    }
};

class D:public B1, public B2
{
public:
    virtual void Funtest3()
    {
        cout << "D::Funtest3" << endl;
    }
};

typedef void (*Vpf)();

void PrintVpf()
{
    D d;
    Vpf* fun = (Vpf*)*(int*)&d;

    cout << endl<< "D类:" << endl;
    while (*fun)
    {
        (*fun)();
        ++fun;
    }

    B2 &b2 = d;//打印B2的虚表
    fun = (Vpf*)*(int*)&b2;
    while (*fun)
    {
        (*fun)();
        ++fun;
    }
}

int main()
{
    cout << "sizeof(B1) = "<<sizeof(B1) << endl;
    cout << "sizeof(D) = "<<sizeof(D) << endl;
    PrintVpf();

    system("pause");
    return 0;
}

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

多继承规则:没有重写的多函数的虚表,先按照继承次序打印第一个基类虚表,在打印派生类新添加的虚表,之后打印第二个基类的虚表。若有重写则转变为单继承问题。

3.虚拟继承:
菱形继承示例模型分析:

//菱形虚拟继承
class B
{
public:
    virtual void Funtest1()
    {
        cout << "B::Funtest1" << endl;
    }

    int _data1;
};

class C1 :virtual public B
{
public:
    virtual void Funtest2()
    {
        cout << "C1::Funtest2" << endl;
    }

    int _data2;
};

class C2 :virtual public B
{
public:
    virtual void Funtest3()
    {
        cout << "C2::Funtest3" << endl;
    }

    int _data3;
};

class D :public C1, public C2
{
public:
    virtual void Funtest4()
    {
        cout << "D::Funtest4" << endl;
    }

    int _data4;
};

typedef void(*Vft)();

void PrintVft()
{
    D d;
    d.C1::_data1 = 1;
    d._data2 = 2;
    d._data3 = 3;
    d._data4 = 4;

    cout << endl << "C1的虚表里存放的虚函数:" << endl;
    //由于D多继承于C1和C2,所以D中的虚函数存放于C1的虚表里
    Vft* fun1 = (Vft*)*(int*)&d;//此处指向的是C1的虚表,包含三个虚函数
    while (*fun1)
    {
        (*fun1)();
        fun1++;
    }

    cout << endl << "C2的虚表里存放的虚函数:" << endl;

    Vft* fun2 = (Vft*)*((int*)&d + 3);//向后偏移12个字节找到C2的虚表指针,包含两个虚函数
    while (*fun2)
    {
        (*fun2)();
        fun2++;
    }

    cout << endl << "B的虚表里存放的虚函数:" << endl;
    Vft* fun3= (Vft*)*((int*)&d + 7);//向后偏移4*3+4*3+4=28个字节找到B的虚表指针,包含一个虚函数
    (*fun3)();
}

int main()
{
    cout << "sizeof(B) = " << sizeof(B) << endl;
    cout << "sizeof(C1) = " << sizeof(C1) << endl;
    cout << "sizeof(C2) = " << sizeof(C2) << endl;
    cout << "sizeof(D) = " << sizeof(D) << endl;

    PrintVft();

    system("pause");
    return 0;
}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fly_bit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值