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

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

  输出结果:

8,12

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

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

  输出结果:

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++程序设计

多态实现的原理------新标准c++程序设计的更多相关文章

  1. 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计

    类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...

  2. 多态的作用-游戏编程展示------新标准c++程序设计

    游戏软件的开发最能体现面向对象设计方法的优势.游戏中的人物.道具.建筑物.场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程.每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方 ...

  3. 正确处理类的复合关系------新标准c++程序设计

    假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...

  4. 类与类之间的两种关系------新标准c++程序设计

    在c++中,类和类之间有两种基本关系:复合关系和继承关系. 复合关系也称为“has a”关系或“有”的关系,表现为封闭类,即一个类以另一个类的对象作为成员变量. 继承关系也称为“is a”关系或“是” ...

  5. 复制构造函数被调用的三种情况------新标准c++程序设计

    1.当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用.例如,下面的两条语句都会引发复制构造函数的调用,用以初始化c2. C c2 (c1); C c2=c1; 这两条语句是等价的.注意 ...

  6. 析构函数的调用------新标准c++程序设计

    示例1: #include<iostream> using namespace std; class CDemo{ public: ~CDemo(){cout<<"d ...

  7. 类型转换构造函数 及使用explicit避免类型自动转换------新标准c++程序设计

    类型转换构造函数:  除复制构造函数外,只有一个参数的构造函数一般可以称作类型转换构造函数,因为这样的构造函数能起到类型自动转换的作用.例如下面的程序: #include<iostream> ...

  8. this指针------新标准c++程序设计

    背景:   c++是在c语言的基础上发展而来的,第一个c++的编译器实际上是将c++程序翻译成c语言程序,然后再用c语言编译器进行编译.c语言没有类的概念,只有结构,函数都是全局函数,没有成员函数.翻 ...

  9. 类的互相包含------新标准c++程序设计

    #include<iostream> using namespace std; class A; class B{ public: void f(A* pt){}; } class A{ ...

随机推荐

  1. mybatis如何防止sql注入(2)

    Mybatis框架下SQL注入漏洞修复建议1. 模糊查询like SQL注入修复建议按照新闻标题对新闻进行模糊查询,可将SQL查询语句设计如下:select * from news where ti ...

  2. ubuntu安装nginx踩坑

    ubuntu安装nginx 安装nginx tar -zxvf nginx-1.15.5.tar.gz -C /usr/local/src 解压 cd /usr/local/src/nginx-1.1 ...

  3. java成神之——集合框架之Maps,Hashtable

    集合 Maps HashMap 创建和初始化map 遍历方式 LinkedHashMap WeakHashMap TreeMap 线程锁 Hashtable 结语 集合 Maps HashMap Ma ...

  4. java事件监听机制2

    今天早上的两点收获: 1.addActionListener(其中的setActionCommand函数就是要对对象进行唯一性的标记,便于消息传来后进行处理.理论上actionlistener可以全部 ...

  5. stm32中断 抢占优先级 和 响应优先级 有什么区别

    与51不同,stm32的中断分类更灵活.51只是按先后顺序大小排列互相打断. stm32中多了响应优先级这一概念. stm32的中断分为 1.抢占(占先)优先级. 2.响应优先级. 1.抢占优先级.抢 ...

  6. bash&nbsp;shell笔记4&nbsp;处理用…

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://twentyfour.blog.51cto.com/945260/521448 知 ...

  7. sql server2008 跨服务器之间复制表数据

    首先2个数据库要能互相访问,在本地数据库用 select * into 新表 from opendatasource('SQLOLEDB','Data Source=远程数据库IP;User ID=用 ...

  8. SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证

    1 SpirngBoot环境搭建 创建一个SpringBoot项目即可,详情参见三少的相关博文 参考博文 -> 点击前往 SpirngBoot项目脚手架 -> 点击前往 2 引入Spirn ...

  9. SpringMVC第二天

    SpringMVC第二天   框架课程 1. 课程计划 1.高级参数绑定 a) 数组类型的参数绑定 b) List类型的绑定 2.@RequestMapping注解的使用 3.Controller方法 ...

  10. 数据库sql 开窗函数

    --本文采用Oracle数据库测试,前4个查询为一组,后2个查询为一组,每组前面的查询是为了推出最后的查询 --创建表,为了简化处理,字段类型都采用varcharcreate table tb_sc( ...