C++中虚函数和非虚函数重载在继承时的区别

来源:互联网 发布:java 高级编程 书籍 编辑:程序博客网 时间:2024/06/05 17:46

这里唯一想说明的一点就是,使用虚函数继承时,当继承类被强转成基类后调用虚函数,调用的还是继承类的虚函数。而重载方式的继承类被强转成基类再调用重载函数,则调用的是基类的函数。废话不多说,上代码:

[cpp] view plaincopy
  1. #include <iostream>  
  2. using namespace std;  
  3. class A {  
  4. public:  
  5.     virtual void fun() { cout << "A::fun" << endl; }  
  6. };  
  7. class AP : A  
  8. {  
  9. public:  
  10.     virtual void fun() { cout << "AP:fun" << endl; }  
  11. };  
  12. class B {  
  13. public:  
  14.     void fun() { cout << "B:fun" << endl; }  
  15. };  
  16. class BP : B  
  17. {  
  18. public:  
  19.     void fun() { cout << "BP:fun" << endl; }  
  20. };  
  21.   
  22. int main(int argc, char* argv[])  
  23. {  
  24.     A  a;  
  25.     a.fun();  
  26.     AP ap;  
  27.     ((A*)&ap)->fun();  
  28.     B b;  
  29.     b.fun();  
  30.     BP bp;  
  31.     ((B*)&bp)->fun();  
  32.     return 0;  
  33. }  

 

这段代码执行的输出是:

A::fun
AP:fun
B:fun
B:fun

 

通过汇编分析主要的代码片段如下:

 

[cpp] view plaincopy
  1. fun_A__fun();  
  2. fun_GetAPFuns(&p_fun_addr);  
  3. (*(void (__cdecl **)(int *))p_fun_addr)(&p_fun_addr);  
  4. fun_B__fun();  
  5. fun_B__fun();  

其中fun_GetAPFuns函数,就是获取AP实例被强转后的函数表地址,函数定义如下:

[cpp] view plaincopy
  1. _DWORD *__cdecl fun_GetAPFuns(_DWORD *p_fun_addr)  
  2. {  
  3.   _DWORD *result; // eax@1  
  4.   fun_GetAFuns(p_fun_addr);  
  5.   result = p_fun_addr;  
  6.   *p_fun_addr = &tag_AP_Funs;  
  7.   return result;  
  8. }  
  9. _DWORD *__cdecl fun_GetAFuns(_DWORD *p_fun_addr)  
  10. {  
  11.   _DWORD *result; // eax@1  
  12.   result = p_fun_addr;  
  13.   *p_fun_addr = &tag_A_Funs;  
  14.   return result;  
  15. }  

 

不难看出,针对((A*)&ap)->fun(); 这行代码调用,实际上是先获取了基类的函数表,然后又被继承类的函数表覆盖了。因此输出结果才会是AP:fun。

而对于直接重载继承的经过强转调用,在编译时就直接替换成基类的函数调用了。


FROM:  http://blog.csdn.net/pendle/article/details/6574445

0 0
原创粉丝点击