4.3 C++虚成员函数表vtable
参考:http://www.weixueyuan.net/view/6372.html
总结:
在C++中通过虚成员函数表vtable实现多态,虚函数表中存储的是类中虚函数的入口地址。
使用多态会降低程序运行效率,使用多态的程序会使用更多的存储空间,存储虚函数表等内容,而且在调用函数时需要去虚函数表中查询函数入口地址,这会增加程序运行时间。
在设计程序时,程序设计人员可以选择性的使用多态,对于有需要的函数使用多态,对于其它的函数则不要采用多态。
通常情况下,如果一个类需要作为基类,并且期望在派生类中修改某成员函数的功能,并且在使用类对象的时候会采用指针或引用的形式访问该函数,则将该函数声明为虚函数。
通过前两节的介绍,想必对多态有一定的了解了。这一节将介绍多态是如何实现的,关于如何实现多态,对于程序设计人员来说即使不知道也是完全没有关系的,但是对于加深对多态的理解具有重要意义,故而在此节中稍微阐述一下多态的实现机制。
在C++中通过虚成员函数表vtable实现多态,虚函数表中存储的是类中虚函数的入口地址。在普通的类中是没有虚函数表的,只有在具有虚函数的类中(无论是自身添加的虚函数还是继承过来的虚函数)才会具有虚函数表,通常虚成员函数表的首地址将会被存入对象的最前面(在32位的操作系统中,存储地址是用4个字节,因此这个首地址就会占用对象的前四个字节的空间)。
例1: #include<iostream>
using namespace std; class base
{
public:
virtual void v1(){ }
virtual void v2(){ }
}; class derived: public base
{
public:
virtual void v1(){ }
virtual void v2(){ }
}; int main()
{
base b;
derived d;
base *p;
p = &b;
p->v1();
p->v2();
p = &d;
p->v1();
p->v2();
return ;
}
我们将两个类定义成例1所示形式,两个类中各有两个虚函数v1和v2,我们将其函数入口地址找到列于下表中:
| 虚成员函数 | 函数入口地址 | 虚成员函数 | 函数入口地址 |
|---|---|---|---|
| base::v1 | 00D15834 | derived::v1 | 00D15844 |
| base::v2 | 00D15838 | derived::v2 | 00D15848 |
虚函数表里面存储的就是虚函数的入口地址。我们再来看主函数,在主函数中先定义了base类对象b,因为b类中有虚函数,因此存在虚函数表,而虚函数表的首地址就存储在对象所在存储空间的最前,具体情况可以见下图。当然声明derived对象d之后,情况也跟下图中一样,同样在对象存储空间中包含虚成员函数表地址。

之后定义了一个基类类型的指针p,当我们通过基类指针p调用虚函数v1或v2时,系统会先去p所指向的对象的前四个字节中寻找到虚函数表地址,之后在内存中找到该虚函数表,然后在表中找到对应函数的入口地址,之后直接访问这个函数了。当p指针指向的是基类对象时,基类的虚函数表将会被访问,基类中虚函数将会被调用。当p指针指向的是派生类对象,则访问的是派生类的虚函数表,派生类的虚函数表中存的是派生类中的虚函数入口地址,因此调用的是派生类中的虚函数。
使用多态会降低程序运行效率,使用多态的程序会使用更多的存储空间,存储虚函数表等内容,而且在调用函数时需要去虚函数表中查询函数入口地址,这会增加程序运行时间。在设计程序时,程序设计人员可以选择性的使用多态,对于有需要的函数使用多态,对于其它的函数则不要采用多态。通常情况下,如果一个类需要作为基类,并且期望在派生类中修改某成员函数的功能,并且在使用类对象的时候会采用指针或引用的形式访问该函数,则将该函数声明为虚函数。
4.3 C++虚成员函数表vtable的更多相关文章
- C++虚成员函数表vtable
介绍一下多态是如何实现的,关于如何实现多态,对于程序设计人员来说即使不知道也是完全没有关系的,但是对于加深对多态的理解具有重要意义,故而在此节中稍微阐述一下多态的实现机制. 在C++中通过虚成员函数表 ...
- 关于C++中虚函数表存放位置的思考
其实这是我前一段时间思考过的一个问题,是在看<深入探索C++对象模型>这本书的时候我产生的一个疑问,最近在网上又看到类似的帖子,贴出来看看: 我看到了很多有意思的答案,都回答的比较好,下面 ...
- C++对象的内存布局以及虚函数表和虚基表
C++对象的内存布局以及虚函数表和虚基表 本文为整理文章, 参考: http://blog.csdn.net/haoel/article/details/3081328 http://blog.csd ...
- C++虚函数表解析(图文并茂,非常清楚)( 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法)good
C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术 ...
- 深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)
本文转载自:http://blog.51cto.com/9291927/2148695 总结: 一.成员函数的内存为什么不会反映在sizeof运算符上? 成员函数可以被看作是类 ...
- C++类成员空间分配和虚函数表
最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...
- [C++] Vtable(虚函数表)
Vtable(虚函数表)
- C++ 虚函数表解析
转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...
- C++虚函数表原理
C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技 ...
随机推荐
- win下使用VM虚拟机安装Linux系统
自己电脑上还是有个自己的虚拟机比较方便,之前用的Ubuntu,发现卡得不行. 现在装了个轻量级的Lubuntu,速度提升了不少. 1.下载Lubuntu,安装. 2.进入,设置root密码,初始化ro ...
- jquery判断设备是否是手机
//判断是否是手机 function IsMobile() { var isMobile = { Android: function () { return navigator.userAgent.m ...
- Windows定时开机并开启工作软件
开启休眠功能 在搜索窗口中输入“cmd.exe”,在结果中看见了“cmd.exe”,右击选择“以管理员权限运行程序”打开“cmd.exe”命令窗口,输入命令“powercfg -h on”即可开启计算 ...
- P3721 [AH2017/HNOI2017]单旋
题目:https://www.luogu.org/problemnew/show/P3721 手玩一下即可AC此题. 结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它 ...
- Ugly Number II leetcode java
问题描述: Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime fa ...
- [pat]数素数
时间限制:1000 ms 内存限制 32768 KB 代码长度限制 100 KB 判断程序 Standard (来自 小小) 题目描述 令Pi表示第i个素数.现任给两个正整数M <= N < ...
- HDu4794 斐波那契循环节
题意:Arnold变换把矩阵(x,y)变成((x+y)%n,(x+2*y)%n),问最小循环节 题解:仔细算前几项能看出是斐波那契数论modn,然后套个斐波那契循环节板子即可 //#pragma GC ...
- DOM与document的区别
DOM: DOM 全称是 Document Object Model,也就是文档对象模型. DOM 就是针对 HTML 和 XML 提供的一个API.什么意思?就是说为了能以编程的方法操作这个 HTM ...
- vue项目 sockjs-node一直报错问题
vue3下 vue.config.js中 devServer: { host: '0.0.0.0', port: 8080, proxy: { '/': { target: 'http://127.0 ...
- RabbitMQ、Redis、Memcache
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...