多态性是面向对象的重要组成部分,利用多态可以设计和实现易于扩展的程序,所谓多态就是一个类函数有多重形态,具有不同功能的函数可以用同一个函数名,实现使用一个函数名调用不同内容的函数,从而返回不同的结果,这就是多态性,多态离不开虚函数的支撑,以下案例本人将深度分析虚函数实现机制,并通过汇编实现虚函数机制。
从系统实现的角度来分析,多态性可分为两类,静态多态与动态多态:
静态多态: 通常是通过函数或运算符的重载实现的,静态多态性又称作编译时的多态性.
动态多态: 动态多态性不在编译时确定调用函数的功能,而是通过虚函数实现,它又被叫做运行时的多态性.
由于对象多态性需要通过虚表和虚表指针来完成,虚表指针被定义到对象首地址前4字节处,虚表指针中保存着虚表的首地址,用于记录和查找虚函数,由于虚表指针的初始化依赖于构造函数,如果用户没有提供默认构造函数,那么编译器会自动增加。
在C++中使用关键字virtual
声明函数为虚函数,我们首先编写一段C++代码,请自行反汇编观察虚函数的特性
#include <iostream> using namespace std;class CVirtual { private : int m_Number; public : virtual int GetNumber () { return m_Number; } virtual void SetNumber (int num) { m_Number = num; } }; int main (int argc, char * argv[]) { CVirtual cv; cv.SetNumber (5 ); printf ("virtual = > %d \n" , cv.GetNumber ()); return 0 ; }
仿写汇编代码。
.386p .model flat,stdcall option casemap:none include windows.inc include kernel32.inc includelib kernel32.lib ; 虚表占据类前4字节 Student struct virtualBase DWORD 0 x DWORD 0 Student ends .data stu Student <> virtual_table DWORD 0,0,0,0,0,0,0dh .code SetNumber PROC SetNumber ENDP GetNumber PROC ret GetNumber ENDP ; 模拟构造函数,初始化虚表指针 Init PROC ; 将虚表指针首地址放入到类的开头位置 mov dword ptr [stu],ecx ; 构建函数表 mov dword ptr [virtual_table],offset GetNumber mov dword ptr [virtual_table+4h],offset SetNumber ret Init ENDP main PROC push ebp mov ebp,esp sub esp,0f4h push ebx push esi push edi lea edi,dword ptr [ ebp - 0f4h ] mov ecx,03dh mov eax,0CCCCCCCCh rep stosd lea ecx,stu ; 获取类的首地址 call Init ; 调用构造函数 pop edi pop esi pop ebx add esp,0f4h mov esp,ebp pop ebp ret main ENDP END main