多态实现的原理------新标准c++程序设计
发布日期:2022-04-04 06:36:21 浏览次数:2 分类:博客文章

本文共 1629 字,大约阅读时间需要 5 分钟。

  “多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定。例子:

#include
    
     using namespace std;class A{
     
public:
int i;
virtual void func(){};
virtual void func2(){};  
  //如果为只有一个去掉 virtual 关键字即virtual void func2(){};变为 void func2(){}; 输出结果不变 仍为 8,12 };
   //当 virtual 关键字都去掉时,结果才为 4,8class B :public 
int j;
void func(){}};int main(){
cout< <<","<

  输出结果:

8,12

  如果将程序中的 virtual 关键字去掉:

#include
    
     using namespace std;class A{
     
public:
int i;
void func(){};
void func2(){};};class B :public A{
int j;
void func(){}};int main(){
cout< <<","<

  输出结果:

4,8

  对比发现,有了虚函数以后,对象占用的存储空间比没有虚函数时多了4个字节。实际上,任何有虚函数的类及其派生类的对象都包含这多出来的4个字节,这4个字节就是实现多态的关键——它位于对象存储空间的最前端,其中存放虚函数表的地址。

  每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该表的任何对象中都放着该虚函数表的指针(可以认为这是由编译器自动添加到构造函数中的指令完成的)。虚函数表是编译器生成的,程序运行时被载入内存。一个类的虚函数表中列出了该类的全部虚函数地址。例如,在上面的程序中,类A对象的存储空间以及虚函数表(假定类A还有其他虚函数)如图

 

  类B对象的存储空间以及虚函数表(假定类B还有其他虚函数)如图

  多态的函数调用语句被编译成根据基类指针所指向的(或基类引用所引用的)对象中存放的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数的一系列指令。

  假设pa的类型是A*,则pa->func()这条语句的执行过程如下:

    (1)取出pa指针所指位置的前4个字节,即对象所属的类的虚函数表的地址(在64位计算机中,由于指针占8个字节,所以要取出8个字节)。如果pa指向的是类A的对象,则这个地址就是类A的虚函数表的地址;如果pa指向的是类B的对象,则这个地址就是类B的虚函数表的地址。

    (2)根据虚函数表的地址找到虚函数表,在其中查找要调用的虚函数的地址。不妨认为虚函数表是以函数名作为索引来查找的,虽然还有更高效的查找方法。如果pa指向的是类A的对象,自然就会在类A的虚函数表中查找A::func的地址;如果pa指向的是类B的对象,就会在类B的虚函数表中查出B::func的地址。类B没有自己的func2函数,因此在类B的虚函数表中保存的是A::func2的地址,这样,即便pa指向类B的对象,"pa->func2();"这条语句在执行过程中也能在类B的虚函数表中找到A::func2的地址。

    (3)根据找到的虚函数的地址调用虚函数。

  由以上过程可以看出,只要是通过基类指针或基类引用调用虚函数的语句,就一定是多态的。也一定会执行上面的查表过程,哪怕这个虚函数仅在基类中有,在派生类中没有。

 

 新标准c++程序设计

转载地址:https://www.cnblogs.com/l2017/p/7823498.html 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:多态的作用-游戏编程展示------新标准c++程序设计
下一篇:c++小知识

发表评论

最新留言

很好
[***.249.68.18]2022年05月22日 13时33分20秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章

java 静态方法的参数_java – 如何在jshell中表示一般多态静态方法的类型参数?... 2019-12-01 15:24:40
在java中 分页的步骤_在javaweb中使用分页查询的详细步骤 2019-12-01 15:24:40
java中有错误咋能快速的改正_java抽象类错了 怎么改正 2019-12-01 15:24:40
java转义括号_关于java:如何转义模式编译的方括号 2019-12-01 15:24:40
java无法读取方案文档_解决Spring的java项目打包后执行出现“无法读取方案文档...“、“原因为 1) 无法找到文档; 2) 无法读取文档; 3) 文档的根元素不是...”问题... 2019-12-01 15:24:40
mysql开启远程登_mysql开启远程登录方法介绍 2019-12-01 15:24:38
stateless java_JAVA -- stateless4j StateMachine 使用浅析(二) 2019-12-01 15:24:38
java 搭建个人博客_5分钟 教大家搭建免费个人博客 2019-12-01 15:24:38
java 循环替代线程_Java 多线程 生产者—消费者 通用模式(synchronized已被Lock替代!)... 2019-12-01 15:24:39
python第3章答案_【Python基础教程】第3章 字符串 2019-12-01 15:24:39
java hibernate 查询_(十)Hibernate 查询方式 2019-12-01 15:24:39
java环形队列_环形队列高效触发大量超时任务的算法实现 2019-12-01 15:24:39
java命令行解析库_Java命令行解析:apache commons-cli 2019-12-01 15:24:36
java gui 结构_java GUI编程 2019-12-01 15:24:36
java 单件_Java语言设计模式学习之单件模式实例讲解 2019-12-01 15:24:37
java在密码错误时不跳转页面_javaweb利用ajax使登录窗口不跳转页面实现对账号密码的判断... 2019-12-01 15:24:37
java类变量调用_JAVA类的方法调用和变量(全套) 2019-12-01 15:24:37
mysql 清理归档日志_oracle归档日志清理 2019-12-01 15:24:37
interrupt java_关于java中的interrupt 2019-12-01 15:24:37
什么是java环境变量_什么是java环境变量 2022-02-03