多态(C++)

多态

概念&作用

  • 多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,就是同一种事物表现出的多种形态
  • 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。
  • 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。
    这里写图片描述

  • 静态多态:编译器在编译期间完成,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用哪个函数,如果有对应的函数就调用函数,否则出现编译错误。

  • 动态多态(动态绑定):在程序执行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
动态绑定的条件:
  • 在基类中是虚函数(使用virtual关键字修饰的类的成员函数),派生类重写基类的虚函数
  • 通过基类的指针或引用调用虚函数
class Base
{
public:
    virtual void Funtest()//虚函数
    {
        cout << "Base::Funtest()" << endl;
    }
    int _b;
};
class Dervied : public Base
{
public:
    virtual void Funtest()//重写
    {
        cout << "Derived::Funtest()" << endl;
    }
    int _d;
};
int main()
{
    Base b;
    b.Funtest();
}

纯虚函数:在成员函数形参列表后写上=0;则成员函数为纯虚函数。
抽象类(接口类):包含纯虚函数的类。
  • 抽象类不能实例化出对象
  • 抽象类必须有类继承,并且重写纯虚函数,派生类才能实例化出对象。
class Base//抽象类
{
public:
    virtual void Funtest() = 0;//纯虚函数
};
继承体系同名函数的关系

这里写图片描述

虚表分析

这里写图片描述
注释:所有函数定义省略,内容都为打印该函数名

派生类的虚函数表生成:
class Base
{
public:
    virtual void Funtest1();
    virtual void Funtest2();
    virtual void Funtest3();
    int _b;
};
class Dervied :  public Base
{
public:
    virtual void Funtest1();
    virtual void Funtest4();
    int _d;
};
int main()
{
    Derived d;
    //类内没有给出构造函数,编译器自动合成构造函数
    //构造函数的作用是将虚表的地址放在前四个字节
    return 0;
}
//汇编语句
    Dervied d;
01374E48  lea         ecx,[d]  
01374E4B  call        Dervied::Dervied (01371500h)  
//调用派生类的构造函数
01371500  jmp         Dervied::Dervied (013733A0h)
//跳转到派生类的构造函数
Dervied::Dervied:
......
013733C6  call        Base::Base (013714F6h)  
//在派生类构造函数中调用基类构造函数
......
013714F6  jmp         Base::Base (01373360h) 
Base::Base:
  • 先拷贝基类的虚函数表
  • 如果派生类重写了基类的某个虚函数,就替换同位置上的基类虚函数
  • 最后跟上派生类自己的虚函数
协变
  • 基类中返回基类的引用或指针
  • 派生类中返回派生类的引用或指针
class B
{
public:
    virtual B& Funtest1();
    int _b;
};
class D : virtual public B
{
public:
    virtual D& Funtest1();
    virtual void Funtest2();
    int _d;
};
不能定义为虚函数情况
void Funtest()
{}
class B
{
public:
    virtual B();//1   构造函数
    virtual static void test();//2   静态成员函数
    virtual friend void Funtest();//3   友元函数
    virtual B& Funtest1();
    int _b;
};
int main()
{
    B b;
    return 0;
}
//编译器报错(vs2013):
//1.
//error C2633: “B”:“inline”是构造函数的唯一合法存储类
//2.
//error C2216: “virtual”不能和“static”一起使用
//3
// error C2575: “Funtest”: 只有成员函数和基可以是虚拟的
析构函数最好定义为虚函数的情况
  • 如果派生类构造函数中申请空间,析构函数中释放空间,析构函数必须定义为虚函数—–防止内存泄漏
最好不要讲operator=定义为虚函数
  • 虽然它可以
不要在构造函数和析构函数中调用虚函数
  • 对象不完整,可能会出现未定义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值