动态绑定,多态(带你从本质了解多态)

简介: 动态绑定,多态(带你从本质了解多态)

在上一章节中,我们讲述了虚函数和虚函数表,我们知道了不管在类中有多少个虚函数,都不会使类的大小扩大,在this指针中,只会多出一个虚函数表的地址,是this指针的第一个内容,在虚函数表中,函数是根据虚函数定义的顺序排列的,在这一章节中,我们将通过深入解析虚函数表,从而从本质上理解多态。


一.深入探索虚函数表

我们知道在虚函数表中存储的是该函数的地址,那么我们该如何验证?

我们可以通过函数指针的方式来调用存储在虚函数表中的函数:

#include "stdafx.h"
class Base{
public:
  int a;
  int b;
  Base(){
    a = 1;
    b = 2;
  }
  void Function_1(){
    printf("Base:Function_1...\n");
  }
  virtual void Function_2(){
    printf("Base:Function_2...\n");
  }
  virtual void Function_3(){
    printf("Base:Function_3...\n");
  }
};
int main(int argc, char* argv[])
{
  typedef void (*Function)(void);
  Base b;
  int* p;
  p = (int*)&b;
  int* function;
  function = (int*)(*p);
  Function pFn;
  for(int i=0;i<2;i++){
    pFn = (Function)*(function+i);
    pFn();
  }
  return 0;
}

这里我们通过函数指针来调用虚函数表中的地址,发现虚函数表中存的确实是虚函数的地址,且顺序是按照定义虚函数的顺序排列的。

1.单继承无函数覆盖下的虚函数表

我们知道在虚函数表中存的只有虚函数的地址,所以我们在写代码的时候不再写构造函数和析构函数,我们只写虚函数

#include "stdafx.h"
class Base{
public:
  int a;
  int b;
  virtual void Function_1(){
    printf("Base:Function_1...\n");
  }
  virtual void Function_2(){
    printf("Base:Function_2...\n");
  }
};
class Sub1:public Base{
public:
  int c;
    virtual void Sub_1(){
    printf("Sub1:Sub_1...\n");
  }
  virtual void Sub_2(){
    printf("Sub2:Sub_2...\n");
  }
};
int main(int argc, char* argv[])
{
  typedef void (*Function)(void);
  Sub1 b;
  int* p;
  p = (int*)&b;
  int* function;
  function = (int*)(*p);
  Function pFn;
  for(int i=0;i<4;i++){
    pFn = (Function)*(function+i);
    pFn();
  }
  return 0;
}

我们看看程序输出窗口:

我们观察代码就能知道,我们通过函数指针调用函数的时候,是根据虚函数表的顺序调用的,所以我们得出结论:

当继承父类的时候,父类的虚函数会在派生类虚函数的上面,且它们的顺序都为定义虚函数的顺序。

2.单继承有函数覆盖下的函数虚表
#include "stdafx.h"
class Base{
public:
  int a;
  int b;
  virtual void Function_1(){
    printf("Base:Function_1...\n");
  }
  virtual void Function_2(){
    printf("Base:Function_2...\n");
  }
};
class Sub1:public Base{
public:
  int c;
  virtual void Function_1(){
    printf("Sub1:Function_1...\n");
  }
  virtual void Sub_1(){
    printf("Sub1:Sub_1...\n");
  }
  virtual void Sub_2(){
    printf("Sub2:Sub_2...\n");
  }
};
int main(int argc, char* argv[])
{
  typedef void (*Function)(void);
  Sub1 b;
  int* p;
  p = (int*)&b;
  int* function;
  function = (int*)(*p);
  Function pFn;
  for(int i=0;i<5;i++){
    pFn = (Function)*(function+i);
    pFn();
  }
  return 0;
}

这里注意一个细节,在通过函数指针调用函数的时候,我写了一个for循坏,并且次数为5,但是在程序运行的时候,它弹出来一个窗口告诉我该地址不可访问,则说明虚函数表里的函数肯定比五个少。

我们来看看程序输出窗口:

这里打印出的函数顺序,实际上就是虚函数表里的函数顺序。

这时候,我们应该记得在课堂上,“铁男“说过一句话:”覆盖的是哪个,就在那个表里“。这里我解释一下:子类Function_1覆盖的是父类的虚函数,那么这个函数就出现在”父类的虚函数表“里(注意这里我们只是形象地称为父类的虚函数表,实际上这里只有一张虚函表哦),但是函数的具体功能是我们后定义的那个函数的功能。

相关文章
|
2月前
|
Java 编译器
多态
多态
16 2
|
3月前
|
存储 编译器 C++
|
6月前
|
存储 安全 编译器
【C/C++ 多态核心 20240115更新】C++虚函数表:让多态成为可能的关键
【C/C++ 多态核心 20240115更新】C++虚函数表:让多态成为可能的关键
51 0
|
6月前
|
NoSQL 编译器 程序员
『 C++类与对象 』虚函数与多态
『 C++类与对象 』虚函数与多态
|
编译器 Linux C++
C++多态
C++多态
|
编译器
多态的初识
多态的初识
|
C++
【C++】非常重要的——多态(一)
【C++】非常重要的——多态
58 0
【C++】多态(上)
【C++】多态(上)
81 0
【C++】多态中虚函数的底层理解
【C++】多态中虚函数的底层理解
【C++】多态中虚函数的底层理解