Administrator
发布于 2022-03-12 / 11 阅读
0
0

关于虚函数的一些总结

关于虚函数的一些总结

说到多态又可以联想到虚函数,虚函数又有很多相关问题,这次做个小总结

1 . 什么是虚函数

  • 虚函数在有多态的前提下才有的特性,现在问题是多态是什么?

多态可以分为:

静态多态:函数重载,根据参数不同,从而调用不同的函数(这里不做重点介绍)

动态多态: 根据操作的对象不同,从而调用不同的函数(使用虚函数实现)

总的来说: 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结

现在看下动态多态是怎么使用:


class Shape {
public:
  Shape() {}
  ~Shape() {}
  virtual void area() {}
};
class Rectangle : public Shape {
public:
  int x, y;
  Rectangle(int a = 0, int b = 0) {
    x = a;
    y = b;
  }
  void area() { cout << " Rectangle area " << x * y << endl; }
};
class Round : public Shape {
public:
  int x, y;
  Round(int a = 0, int b = 0) {
    x = a;
    y = b;
  }
  void area() { cout << " Rount area " << 3.14 * y << endl; }
};
int main() {
  Shape *t;
  Round r(1, 2);
  Rectangle y(2, 3);
  t = &r;  //基类指针指向 Round 类r
  t->area(); //Rount area 6.28
  t = &y;  // 基类指针指向 Rectangle
  t->area(); // Rectangle area 6
  system("pause");
  return 1;
}

基类用 virtual 声明了函数,用基类的指针指向不同的派生类,然后基类的指向的函数也有不同的效果

那这个的原理是怎样的呢?即虚函数如何实现的?

如果一个带有虚函数的类的大小他的大小是多大呢?

!image-20220314163106660

先不说为什么空类大小为1 ,我们先说带有虚函数的类大小为4, 因为带有虚函数的类有一个 指向函数数组 的指针,而指针是4个字节的,指针指向的数组可以函数,那么能否直接自己直接通过指针来调用虚函数呢? 答案是可以的

!image-20220315144827997

如上图所示,用通过 base 实例化的 b地址 可以调用类中的虚函数,通过偏移值的不同,调用不同的函数 ,可以看出 实例化后的 b是有个指针指向一个指针数组 ,就该base类而言,内存布局如下:

!image-20220315150631707

现在我们知道了虚函数表的如何存在的,那如何通过这个实现多态的呢?

用一个基类的指针指向派生类时候,如果派生类中有函数重载了父类的虚函数,则会替换虚函数表中对应的函数

就是说 : 假如派生类也有函数 f(); 此时 虚表中 f()的函数地址 会被 派生类的 f() 函数替换(也称为动态联编)

与基类指针 指向 f() 时,执行的是派生类的 f()

!image-20220315152052778

大致上的原理 就这样,其实还有多细节没有补充,想着通过反汇编来看下动态联编是怎么实现,后续再来吧..

一些虚函数的问题

什么函数不能声明为虚函数

  1. 构造函数

虚表指针的初始化时在构造函数进行的,而虚函数需要放到虚表中。在调用虚函数前,必须首先知道虚表指针,所以不行

  1. 普通函数

虚函数需要在继承多态下使用才有意义

  1. 静态函数

静态函数可以直接调用不需要指针

  1. 内联函数

内联函数属于静态联编,即是编译阶段就确定调用哪个函数了,虚函数是动态联

  1. 友元函数

有元函数不支持继承


评论