c++ 虚函数的实现机制
转载自:http://blog.csdn.net/jiangnanyouzi/article/details/3720807
1、c++实现多态的方法
其实很多人都知道,虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,每个类的对象用了一个虚指针。具体的用法如下:
class A
{
public:
virtual void f();
virtual void g();
private:
int a
};
class B : public A
{
public:
void g();
private:
int b;
};
//A,B的实现省略
因为A有virtual void f(),和g(),所以编译器为A类准备了一个虚表vtableA,内容如下:
A::f 的地址 |
A::g 的地址 |
B因为继承了A,所以编译器也为B准备了一个虚表vtableB,内容如下:
A::f 的地址 |
B::g 的地址 |
注意:因为B::g是重写了的,所以B的虚表的g放的是B::g的入口地址,但是f是从上面的A继承下来的,所以f的地址是A::f的入口地址。
然后某处有语句 B bB;的时候,编译器分配空间时,除了A的int a,B的成员int b;以外,还分配了一个虚指针vptr,指向B的虚表vtableB,bB的布局如下:
vptr : 指向B的虚表vtableB |
int a: 继承A的成员 |
int b: B成员 |
当如下语句的时候:
A *pa = &bB;
pa的结构就是A的布局(就是说用pa只能访问的到bB对象的前两项,访问不到第三项int b)
那么pa->g()中,编译器知道的是,g是一个声明为virtual的成员函数,而且其入口地址放在表格(无论是vtalbeA表还是vtalbeB表)的第2项,那么编译器编译这条语句的时候就如是转换:call *(pa->vptr)[1](C语言的数组索引从0开始哈~)。
这一项放的是B::g()的入口地址,则就实现了多态。(注意bB的vptr指向的是B的虚表vtableB)
另外要注意的是,如上的实现并不是唯一的,C++标准只要求用这种机制实现多态,至于虚指针vptr到底放在一个对象布局的哪里,标准没有要求,每个编译器自己决定。我以上的结果是根据g++ 4.3.4经过反汇编分析出来的。
2、两种多态实现机制及其优缺点
除了c++的这种多态的实现机制之外,还有另外一种实现机制,也是查表,不过是按名称查表,是smalltalk等语言的实现机制。这两种方法的优缺点如下:
(1)、按照绝对位置查表,这种方法由于编译阶段已经做好了索引和表项(如上面的call *(pa->vptr[1]) ),所以运行速度比较快;缺点是:当A的virtual成员比较多(比如1000个),而B重写的成员比较少(比如2个),这种时候,B的vtableB的剩下的998个表项都是放A中的virtual成员函数的指针,如果这个派生体系比较大的时候,就浪费了很多的空间。
比如:GUI库,以MFC库为例,MFC有很多类,都是一个继承体系;而且很多时候每个类只是1,2个成员函数需要在派生类重写,如果用C++的虚函数机制,每个类有一个虚表,每个表里面有大量的重复,就会造成空间利用率不高。于是MFC的消息映射机制不用虚函数,而用第二种方法来实现多态,那就是:
(2)、按照函数名称查表,这种方案可以避免如上的问题;但是由于要比较名称,有时候要遍历所有的继承结构,时间效率性能不是很高。(关于MFC的消息映射的实现,看下一篇文章)
3、总结:
如果继承体系的基类的virtual成员不多,而且在派生类要重写的部分占了其中的大多数时候,用C++的虚函数机制是比较好的;
但是如果继承体系的基类的virtual成员很多,或者是继承体系比较庞大的时候,而且派生类中需要重写的部分比较少,那就用名称查找表,这样效率会高一些,很多的GUI库都是这样的,比如MFC,QT
PS. 其实,自从计算机出现之后,时间和空间就成了永恒的主题,因为两者在98%的情况下都无法协调,此长彼消;这个就是计算机科学中的根本瓶颈之所在。软件科学和算法的发展,就看能不能突破这对时空权衡了。呵呵
何止计算机科学如此,整个宇宙又何尝不是如此呢?最基本的宇宙之谜,还是时间和空间~
c++ 虚函数的实现机制相关推荐
- C++中的虚函数(表)实现机制以及用C语言对其进行的模拟实现
C++中的虚函数(表)实现机制以及用C语言对其进行的模拟实现 声明:本文非博主原创,转自https://blog.twofei.com/496/,博主读后受益良多,特地转载,一是希望好文能有更多人看到 ...
- C++面试题之虚函数(表)实现机制
前言 大家都应该知道C++的精髓是虚函数吧? 虚函数带来的好处就是: 可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时决定该调用基类的函数还是继承类的函数. ...
- (一图胜千言)虚函数实现机制(Vptr, Vtbl)
1. 摘要 讲解C++中虚函数的实现机制,主要是Vptr和Vtbl的讲解,有了虚函数才可以拥有像多态这种强大的功能. 虚函数主要是出现在类的继承体系中. 2.虚指针vptr和虚表vtbl 虚指针及虚表 ...
- 虚函数的特点、实现机制以及vTable、vPointer的使用
虚函数能够实现动态联编,是多态的实现形式之一,相同的函数根据对象的不同可以实现不同的功能.本文重点阐述虚函数的实现.注意事项.实现机制. 虚函数的实现 头文件: #include <iostre ...
- C++ 虚函数实现机制
转 C++面试题之虚函数(表)实现机制 前言 大家都应该知道C++的精髓是虚函数吧? 虚函数带来的好处就是: 可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时 ...
- 虚函数的作用及其底层实现机制
1. C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函 ...
- C++中最好不要在构造函数和析构函数中调用虚函数!!!
1.最好不要在基类和派生类的构造和析构函数中调用虚函数,不会出现多态性 实例如下: #include "iostream"using namespace std;class Bas ...
- 关于虚函数的应用(10个例子)
虚函数是C++中非常重要的一个概念,它最大的好处是能够触发动态绑定.C++中的函数默认不使用动态绑定,要触发动态绑定,必须满足 两个条件: 第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默 ...
- 【转】c++虚函数实现原理
[转]c++虚函数实现原理 原文链接:https://blog.csdn.net/neiloid/article/details/6934135 C++中的虚函数的作用主要是实现了多态的机制.关于多态 ...
最新文章
- [CTSC2018]混合果汁 二分 套 主席树上二分
- python守护进程进程池_Python进程池非守护进程?
- 自适应分辨率可扩展二层JS下拉菜单
- python输出方格_Python蓝桥杯练习 剪格子
- VTK:循环收缩用法实战
- Qt Creator建立和运行
- Rabbits UVALive - 8211
- C语言代码规范(八)使用const修饰值不允许改变的变量
- markdown编辑器 使用语法
- clion opencv安装_Mac 下搭建 Clion + OpenCV4.x 的开发环境
- 笔记本安装linux无线网卡,笔记本安装centos7 无线网卡启动不起来,那位大神看看?...
- 编译原理与编译构造 LR文法
- 运放放大倍数计算公式_16个问题讲透了运算放大器基础的知识点
- 站内信“数据库设计思路”
- 我同意 三江方士 对 哥德巴赫猜想 的 看法
- PB关于打印机纵向横向打印的设置
- 内插和数字上变频技术
- linux上项目运行日志导致磁盘空间不够的问题
- 第三章 μC/OS-Ⅱ中的任务
- signature=1eff1aaee251c280dde2d73a420031b7,Signature of the orthogonal companion in Kreĭn spaces.
热门文章
- SMMS 2016 啟用深色主題
- Golang 处理 Json(二):解码
- [C++]有关深复制与copy constructor的一些问题与实例
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (二) —— SQLite...
- asp.net web services
- 今天拿到了同事给我买的《java与模式》
- Node.js+Koa开发微信公众号个人笔记(一)准备工作 - ZhangCui - 博客园
- VUE的element-ui的使用
- Liunx 中tr的用法
- 【重磅】Google官方推出了免费的、中文的、机器学习初级课程。