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

简介: 动态绑定,多态(带你从本质了解多态)
3.多继承无函数覆盖下的虚函数表

看完了单继承,我们来看看多继承的虚函数表:

#include "stdafx.h"
class Base1{
public:
  int a;
  int b;
  virtual void Base1_1(){
    printf("Base1:Function_1...\n");
  }
  virtual void Base1_2(){
    printf("Base1:Function_2...\n");
  }
};
class Base2{
public:
  int c;
  int d;
  virtual void Base2_1(){
    printf("Base2:Function_1...\n");
  }
  virtual void Base2_2(){
    printf("Base2:Function_2...\n");
  }
};
class Sub1:public Base1,Base2{
public:
  int e;
  virtual void Sub_1(){
    printf("Sub1:Sub_1...\n");
  }
  virtual void Sub_2(){
    printf("Sub1: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<6;i++){
    pFn = (Function)*(function+i);
    pFn();
  }
  return 0;
}

根据我们上面的讲解,应该在虚函数表中有6个函数地址,但是程序在运行的时候照样提醒我:该地址不允许访问,说明在虚函数表中,不足6个函数。

我们看看程序输出窗口:

那么到底哪里出了问题?父类Base2中的虚函数去哪了?

我们先来看一下Sub的大小:

#include "stdafx.h"
class Base1{
public:
  int a;
  int b;
  virtual void Base1_1(){
    printf("Base1:Function_1...\n");
  }
  virtual void Base1_2(){
    printf("Base1:Function_2...\n");
  }
};
class Base2{
public:
  int c;
  int d;
  virtual void Base2_1(){
    printf("Base2:Function_1...\n");
  }
  virtual void Base2_2(){
    printf("Base2:Function_2...\n");
  }
};
class Sub1:public Base1,Base2{
public:
  int e;
  virtual void Sub_1(){
    printf("Sub1:Sub_1...\n");
  }
  virtual void Sub_2(){
    printf("Sub1:Sub_2...\n");
  }
};
int main(int argc, char* argv[])
{
  printf("%d",sizeof(Sub1));
  return 0;
}

我们可以看到程序输出窗口输出了28,我们来看看Sub的成员:继承了Base1的a和b,继承了Base2的c和d,自己的成员e,还有一张虚表,应该一共是24,可是它为什么输出了28?

其实通过课堂上老师的讲解我们已经知道:多重继承函数时会有多张虚表,而Base2的虚表就存在于this指针的第二个成员,他是Base2的虚表。

二.前期绑定和后期绑定

我们知道当程序调用函数的时候,有两种调用方式,一种是直接调用函数的地址,这种地址在程序编译的时候就已经写死了,另一种是通过一个地址,间接调用函数。

这里介绍一个名词:绑定,将函数与地址链接在一起的过程,叫做绑定。

直接调用函数的方式,在编译时就已将函数与地址绑定,我们称为(前期)编译期绑定

间接调用函数的方式,在运行的时候才进行绑定,我们称这种方式为(运行期)动态绑定或者晚绑定

注意:

只有virtual函数是动态绑定

三.多态

了解了前面的过程,多态的概念这里一句话就明白了:动态绑定还有另一个名字:多态。

这里给出多态的书面定义:

C++中的多态分为静态多态和动态多态。静态多态是函数重载,在编译阶段就饿能够确定调用哪个函数。动态多态是由继承产生的,指同一个属性或行为在基类和各派生类中具有不同的语义,不同的对象根据所接受的消息做出不同的响应,这种现象称为多态。

多态的实现需要满足三个条件:

(1)基类中声明虚函数

(2)派生类重写基类的虚函数

(3)将基类指针指向派生类对象,通过基类指针访问虚函数

我们来看看多态的具体实现,看看多态到底是什么:

#include "stdafx.h"
class Base{
public:
  int x;
  Base(){
    x=100;
  }
  virtual void Base_1(){
    printf("Base:Function_1...\n");
  }
  virtual void Base_2(){
    printf("Base:Function_2...\n");
  }
};
class Sub:public Base{
public:
  int e;
  Sub(){
    x=200;
  }
  virtual void Base_1(){
    printf("Sub1:Sub_1...\n");
  }
};
void Test(Base* p){
  int n = p->x;
  printf("%d\n",n);
  p->Base_1();
  p->Base_2();
}
int main(int argc, char* argv[])
{
  Base b;
  Base* p = &b;
  Test(p);
  return 0;
}

首先我们定义了一个基类对象,并且通过基类指针去访问函数,我们来看看程序输出框:

我们定义了基类对象,并且通过基类指针去访问函数,当然是没有任何问题的。

接下来我们看看多态的实现:

创建一个基类,再创建一个派生类,将基类函数覆盖,通过基类指针访问派生类:

#include "stdafx.h"
class Base{
public:
  int x;
  Base(){
    x=100;
  }
  virtual void Base_1(){
    printf("Base:Function_1...\n");
  }
  virtual void Base_2(){
    printf("Base:Function_2...\n");
  }
};
class Sub:public Base{
public:
  int e;
  Sub(){
    x=200;
  }
  virtual void Base_1(){
    printf("Sub1:Sub_1...\n");
  }
};
void Test(Base* p){
  int n = p->x;
  printf("%d\n",n);
  p->Base_1();
  p->Base_2();
}
int main(int argc, char* argv[])
{
  Sub b;
  Base* p = &b;
  Test(p);
  return 0;
}

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

我们可以看到,基类中属性的值也被改变,并且基类中函数也被覆盖,这就是我们所说的多态,同一个属性或行为在基类和各派生类中具有不同的语义,不同的对象根据所接受的消息做出不同的响应。

相关文章
多态和动态绑定的区别是什么?
【10月更文挑战第14天】多态和动态绑定是面向对象编程中两个重要的概念,但它们有着不同的含义和作用。
292 57
|
存储 网络协议 Ubuntu
如何在 Ubuntu 14.04 上使用 Iptables 实现基本防火墙模板
如何在 Ubuntu 14.04 上使用 Iptables 实现基本防火墙模板
270 0
|
3天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1310 3
|
4天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
644 3
|
5天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
|
11天前
|
编解码 人工智能 自然语言处理
⚽阿里云百炼通义万相 2.6 视频生成玩法手册
通义万相Wan 2.6是全球首个支持角色扮演的AI视频生成模型,可基于参考视频形象与音色生成多角色合拍、多镜头叙事的15秒长视频,实现声画同步、智能分镜,适用于影视创作、营销展示等场景。
755 5