C++之多态和虚函数

多态

在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。
多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。(百度百科)
换一种说法:基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,
或者说有多种表现方式,我们将这种现象称为多态(Polymorphism)。
构成多态的条件(必要)

  • 必须存在继承关系
  • 继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)
  • 存在基类的指针,通过该指针调用虚函数
虚函数

可以说虚函数才是实现多态的关键内容。
没有虚函数的情况下,把一个派生类对象赋给基类指针,基类指针只能访问到自己已经有的内容,更尴尬的是
如果基类指针调用的函数在派生类中有同名函数,那么基类指针也只会调用自己函数。

  • 只需要在虚函数的声明处加上 virtual 关键字,函数定义处可以加也可以不加
  • 为了方便,可以只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽关系的同名函数都将自动成为虚函数
  • 构造函数不能是虚函数,派生类不能继承基类的构造函数,将构造函数声明为虚函数没有什么意义,另一个原因:
    在执行构造函数之前对象尚未创建完成,虚函数表尚不存在,也没有指向虚函数表的指针,所以此时无法查询虚函数表,也就不知道要调用哪一个构造函数
    *析构函数可以声明为虚函数,而且有时候必须要声明为虚函数,且大部分情况下都应该将基类的析构函数声明为虚函数
    原因:只有这样在多态的情况下,才能保证各个基类和派生类的析构函数执行到
纯虚函数(一定意义上的接口)
  • 语法格式virtual 返回值类型 函数名 (函数参数) = 0,也就是说只有虚函数才能这么写
  • 有纯虚函数的类无法实例化,也就是无法创建对象
  • 派生类必须实现它(否则编译器直接报错),才能被实例化
  • 纯虚函数可以在基类写实现,但是没有意义,因为无法实例化

关于虚基类表和虚函数表,简单总结一下

(本质还是为了根据指针和偏移找到相应的对象)

  • 虚继承的对象在内存模型上会增加一个叫vbptr的指针
  • 有虚函数的对象在内存模型上会增加一个vfptr的指针(菱形虚继承时会有坑,参考下一篇知乎大神的回答)
  • VC和G++实现不一样,G++二者合一了