C++对象模型之虚函数实现原理
来源:互联网 发布:软件流程图画图工具 编辑:程序博客网 时间:2024/06/08 08:40
在C++中,多态(polymorphism)的意思是,用基类的指针或者引用,寻址出一个派生类对象。而虚函数(virtual member function)是多态的基础,这也是面向对象编程迷人之处。现在刚好有时间,就写一下自己对C++在单一继承情况下如何实现虚函数的肤浅认识。
一旦一个类有一个虚函数,那么一定会建立一个虚表(virtual table),虚表里面有所有虚函数的地址。虚表是该类所有对象共享的,每个对象都有一个虚指针(vptr),指向虚表。虚指针的设定与重置,是由类的构造函数与析构函数以及复制运算符(copy assignment)自动完成的。
虚表是虚函数的基础。表格有很多槽(slot),通常第一个槽位存放的是每一个类所关联的类型信息(type_info object),用来支持运行时类型识别(RTTI)。
class Demo{public:Demo();virtual ~Demo();virtual void f1();virtual void f2();void f3();static void f4();private:static int ival;long lval;};
图1 Demo类的对象内存布局
每个对象内部都会存储非静态成员变量以及虚指针,其它成员都会在对象外部存储,这些不是这次要讨论的内容。
在C++中,虚函数在编译器间获知,而且这些虚函数的地址是固定不变的,执行期不可能新增或者被替换。为了找到函数的地址,每一个虚函数都会有一个在虚表里面的索引号。
如果继承基类的过程中,派生类决定不改写某个虚函数,那么它就会继承基类这个函数的实体(定义),此时,在这个派生类的虚表中存放的就是基类的该函数。否则,如果派生类重写了基类的某个虚函数,那么派生类的虚表中存放的就会是对此虚函数重新定义的实体。如下图所示。
class Base{public:virtual void x();virtual void y();int ival;};//单一继承class Derived: public Base{public:void x();virtual void z();long lval;};
图2 单一继承情况下的虚表
特别要注意的是:
1)如果是继承基类声明的虚函数实体,那么该函数实体就会被拷贝到派生类虚表相对应的槽位上。
2)如果是使用自己的函数实体,也就是改写基类的虚函数,那么也必须把这个函数实体地址放到相对应的槽位上。
3)如果是新增加一个虚函数,那么虚表就会增加一个slot,并把新的虚函数实体放进这里。
所以,假设对于上面的例子,我们有这样的用法:
ptr->x();
我们不知道ptr是Base还是Dervied指针,也就无法由ptr取得该对象的虚表,但是,我知道每一个x()函数的地址都会放在#1槽位上,所以,编译器会将该调用转换成
(*ptr->vptr[1])(ptr);
上面的表达式中,唯一需要在执行期才能知道的东西是,槽位1是哪个类虚表的,一旦知道了,那么便可调用相应的函数体了。
就写到这。
多重继承与虚拟继承下,虚函数的实现就没那么容易了。下次有空写一下。
- C++对象模型之虚函数实现原理
- C++对象模型之RTTI的实现原理
- C++对象模型之RTTI的实现原理
- C++对象模型之虚函数表
- 【C++对象模型】之虚函数详解
- 【C++】虚函数在不同继承方式中的对象模型
- 实现多态——虚函数的对象模型
- 深度探索C++对象模型之:理解虚函数机制
- 【C++】深度探索C++对象模型之虚拟成员函数(virtual member function)
- c++对象模型笔记之构造函数
- C++对象模型之构造函数
- C++ - 对象模型之 成员函数调用
- C++对象模型之拷贝构造函数
- 【C++】虚函数原理
- C++ 多态的实现原理--虚函数表
- 虚函数实现原理
- 虚函数实现原理
- 虚函数实现原理
- 遍历下Request.ServerVariables
- 2017:字符串统计
- android开发——环境搭建
- 数组与指针的关系与区别
- django_细节
- C++对象模型之虚函数实现原理
- error C2471: 无法更新程序数据库
- django_剖析
- 用智能工作流和3D打印系统建设快速生产系统(RPS)的构想
- Linux Shell常用技巧(目录)
- Js window.document 的属性、方法和事件汇总
- 如何安装/升级Opatch
- C++开源学习-Ptypes
- 看图片 读故事:轻松理解数字签名和数字证书