虚函数·多态·重写


虚函数机制

  • 父类的指针或引用指向子类的对象,优先调用子类成员,没有再调用父类成员
  • 虚函数允许函数调用与函数体的联系在运行时才给出,可以实现同一接口,多种实现。(可以使用父类去统一的管理子类对象,从而减轻了我们去对每一个对象单独管理的负担)
  • 虚函数是一种动态的多态,属于动态联编。

典型例题:虚函数和多态实现

注意:基类指针指向的是派生类对象的地址,注意对象前的& 取址符

image.png

动态链编与静态链编


静态链编:在程序编译链接阶段进行链编,程序运行前,确定函数的调用与执行。
调用条件:

  • 基类的指针或引用指向派生类对象
  • 调用虚函数

动态链编:指在程序运行时进行的,在程序运行时确定函数的调用与执行。
继承是动态链编的基础,虚函数是动态链编的关键。

虚析构函数


虚析构函数

  • 基类的析构函数为虚函数,其派生类中的析构函数也是虚函数;
  • detele普通基类指针只会调用父类的析构函数,子类的不会被调用
  • delete基类的虚析构函数,且派生类有自定义析构函数实现时,delete基类指针时会同时调用派生类的析构函数;
  • 派生类析构的时候,会自动调用基类的析构函数

将析构函数设置成虚函数是: 为了释放父类指针指向的子类对象时,调用子类的析构函数
image.png

纯虚函数&抽象类


纯虚函数:

  • 是一种特殊的虚函数,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,他的实现留给父类的子类去做;
  • 含有纯虚函数的类称为抽象类,抽象类不能定义对象(不能实例化);抽象类最少有一个纯虚函数
  • 写法:virtual void function()=0;
  • 构造函数不能是虚函数,析构函数可以是虚函数;

抽 象 类:

  • 使用抽象类的目的是统一接口,让所有子类实现这个接口
  • 抽象类只能作为基类来使用,不能声明抽象类的对象;
  • 抽象类不能用于直接创建对象实例,可以声明抽象类的指针和引用
  • 我们子类对象需要一个父类指针去管理他们,父类中的虚函数又确实没有实现的代码;支持多态性
  • 继承自抽象类的子类如果没有实现父类的所有纯虚函数,仍然是抽象类

image.png


一个类对象中存在多少个虚函数表和什么有关?
直接继承了多少个虚函数的父类,就有多少个虚函数表
什么时候会向虚函数表内添加内容

1. 子类原直接继承父类的虚函数时,会根据有位置放置到对应的表中
2. 子类重写父类虚函数的时候,会找到对应父类的虚函数表,覆盖
3. 子类添加自己的虚函数时,会添加到第一张表的结尾


虚函数对于类大小的影响

类中 空函数 1个 字节
类中有一个虚函数 多出4个字节(放置的指向虚函数表的指针);
如果父类和子类函数同名,子类的虚函数表的指针与父类虚表指针放在同一个4字节内
如果是两个 父类的话,会分别建立两个独立的虚表,即8个字节

重载 重定义 重写


1.重载:在同一个作用域内,函数名相同,参数不同(参数类型,参数个数)
(C++编译器的名称粉碎机制,根据函数参数的不同,把函数修改称不同的名字)
image.png
2.重定义 :普通继承,子类父类具有同名函数,会使用子类的函数,屏蔽父类的函数。

  1. class A{
  2. public:
  3. voidf(){cout << "A" << endl; }
  4. public:
  5. int _x;
  6. };
  7. class B : public A
  8. {
  9. public:
  10. void f(int a)
  11. {
  12. cout << "B" << endl;
  13. }
  14. public:
  15. int _x;
  16. };
  17. voidtest1()
  18. {
  19. B b;
  20. b.f();
  21. }

3.重写

  • (多态)子类函数名相同,参数类型相同,父类声明virtual(有虚函数)
  • 父类的指针或引用指向子类对象,就会调用子类的虚函数

image.png

  1. 重载
  2. 1、函数在同一作用域里
  3. 2、函数名相同/参数不同
  4. 3、返回值可以不同
  5. 重写(覆盖)
  6. 1、函数不在同一作用域里(两个函数分别在父类和子类里)
  7. 2、函数名相同/参数列表相同/返回值相同(协变除外)
  8. 3、基类函数必须是虚函数(有关键字virtual
  9. 4、访问修饰符可以不同
  10. 重定义(隐藏)
  11. 1、函数在不同作用域里(分别在父类和子类里)
  12. 2、函数名相同
  13. 3、在基类和派生类不构成重写那就是重定义

image.png

虚函数表 虚表指针


虚函数表

  • 虚函数表指针指向的是虚函数表
  • 同一个类的多个对象在一个虚函数表中
  • 虚函数表是以类为单位的,子类继承自多少个父类,就有多少张虚函数表,一般情况下一个表占4字节(对齐问题)

image.png