c++ 虚函数实现原理简单剖析
来源:互联网 发布:c语言管理系统源代码 编辑:程序博客网 时间:2024/05/29 04:53
虚函数在C++里的作用是在是非常非常的大,很多讲述C++的文章都会讲到它,要用好C++,就一定要学好虚函数。本文对虚函数的一些实现机制,以及C++对象布局做一下探索。
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。那么,这个动态联编是怎么实现的呢?
下面看一个简单例子:
class AA{
public:
virtual void fun(){printf("In AA");}
virtual void fun1(){printf("In AA1");}
};
class BB :public AA{
public:
int i,j;
void fun(){printf("In BB");return 0;}
void ff(){};
};
class CC :public AA{
public:
void fun1(){printf("In CC1");return 0;}
void fun(){printf("In CC");return 0;}
};
首先要明确的是,在有虚函数的类中,有一个隐藏的成员指针变量vfptr,虚函数的神秘之处就在于这个东西。这是一个指针,它是指向虚函数表的指针,好啦,又出现了一个新词,虚函数表,它就是存放虚函数地址的一张表,(不用关心它的数据结构是咋样的)。可以通过这个虚函数表找到虚函数的入口地址。ok,名词解释完毕.(我有点废).
总的说来就是,在有虚函数的类中,一定会有一个虚函数表指针vfptr,这个vfptr指针会放在类的起始处,虚函数表里会按基类声明虚函数的顺序在vfptr里存放虚函数的地址,虚函数表里存放的是虚函数的地址,是具体子类的实现函数的地址。调用虚函数的时候,是从vfptr所指的函数表里获取到函数地址,然后才调用具体的代码。
当把一个继承类的指针赋值给基类指针时,基类的指针就指向了继承类的内存,此时的vfptr就是继承类的vfptr啦。因此,通过基类指针调用虚函数的时候就找到的是继承类的虚函数地址。调用的式继承类的虚函数。如果继承类没有重载基类的某个虚函数,如class BB,则继承类就是直接继承的基类的那个虚函数。
ok,下面来看一下类内存布局,使用Microsoft Visual Studio的cl命令可以简单看到类的内存布局。
即:使用命令 cl demo.cpp /d1reportSingleClassLayoutCC (CC为你想查看的类名)可查看类的内存布局。
////////////class AA memory layout////////////////////
class AA size(4):
+---
0 | {vfptr}
+---
AA::$vftable@:
| &A_meta
| 0
0 | &AA::fun
1 | &AA::fun1
AA::fun this adjustor: 0
AA::fun1 this adjustor: 0
////////////class BB memory layout////////////////////
class BB size(12):
+---
| +--- (base class
0 | | {vfptr}
| +---
4 | i
8 | j
+---
BB::$vftable@:
| &BB_meta
| 0
0 | &BB::fun
1 | &AA::fun1
BB::fun this adjustor: 0
/////////////////////////class c memory layout////////////////////
class CC size(4):
+---
| +--- (base class
0 | | {vfptr}
| +---
+---
CC::$vftable@:
| &CC_meta
| 0
0 | &CC::fun
1 | &CC::fun1
CC::fun1 this adjustor: 0
CC::fun this adjustor: 0
综上可知,类的虚函数表的结构和其基类的虚函数表结构一致。(顺序一致)
如果继承类没有重载某个基类的虚函数,
则在继承类的虚函数表中依然会保存其基类的那个虚函数的地址。它是直接继承基类的虚函数。非虚函数不出现在类的内存布局里。
注意每个类后面的size(*);这个东西。这个是说的是类占用多少内存,即使用sizeof(类变量)得到的结果就是这个size。我们来看看,class AA的size是4,咦,明明该是1(如果没有虚函数的类中没有成员变量sizeof结果就是1,不要问我,MicrosoftVisual Studio这么说的)怎么是4咧,细心的童鞋可能已经发现,刚刚谈到了class A还有一个隐藏的成员指针变量vfptr。因此,class B的size是12就不足为奇了。ok就这样吧,鄙人不才,有不对之处请各位童鞋多多指正。谢谢
参考: 1. http://c.chinaitlab.com/cc/basic/200908/790967.html
2.以前看过的N多书
- c++ 虚函数实现原理简单剖析
- RetargetAction实现原理简单代码剖析
- MJExtension底层实现原理简单剖析
- 简单实现一个进度条并剖析原理
- JVM原理简单剖析
- super函数没有那么简单-super原理剖析
- inline hook原理简单剖析和实现(dll)
- 实现注入view,简单案例剖析butterknife原理
- Ring实现原理剖析
- 剖析Vue实现原理
- 【C++】虚函数原理
- 【STL】list的简单剖析以及各种函数的实现
- 【STL】list的简单剖析以及各种函数的实现
- 【STL】verctor的简单剖析以及各种函数的实现
- 剖析C++多态:用C实现简单多态
- C++ 多态的实现原理--虚函数表
- 简单c语言小游戏实现原理
- c++构造函数中调用虚函数的原理剖析
- 将GridView的内容导出到Excel中
- 4+1视图方法的3大特点——4+1视图剖析系列
- 使用FLEX3开发大型多人在线游戏
- Java实现数组排序总结篇(冒泡,选择,插入,希尔)
- 终于把自己的flex环境搭起来了,
- c++ 虚函数实现原理简单剖析
- 【刘翔四连冠将是中国田径的悲哀】
- js显示当前日期
- 条款53:不要轻忽编译器的警告
- 认识QT程序
- 表达式求值 数据结构 C/C++ 栈的应用
- Maven2上演狸猫换太子――字符编码造成的诡异故障
- 用指针访问数组
- VB Split 函数在 Delphi 中的不完全实现