C++虚函数原理及函数调用栈模型
精简原文:http://blog.csdn.net/haoel/article/details/1948051/
关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
1.Base中3个虚函数,Derive中3个虚函数:
1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。
2.Derive重载f()后:
1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
2)没有被覆盖的函数依旧。
3.多重继承后:
1) 每个父类都有自己的虚表。
2) 子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的)
4.函数调用栈模型
具体来说,从内存的角度看,函数h调用f时,Stack是按下面步骤发生变化的:
- 实参按照从右向左的顺序一个一个进入stack中。
- 函数调用指令之后的“下一条指令地址”进入stack中。(pRetAddr)
- EBP(栈指针)指向调用此函数的函数栈地址。(FuncB's EBP)
- 函数f中的局部变量加入到stack中。
- 函数f中的局部变量从Stack中弹出。
- “下一条指令地址”从stack中弱出,流入程序计数器寄存器IP中。
- 寄存器AX/EAX/RAX中的值流入到stack中h的局部变量(或者全局变量等)中。(返回值)
- 调用函数f时的实参从stack中弹出。