C++中虚函数和非虚函数重载在继承时的区别 - 每天进步一点点就好 - 博客频道 - youkuaiyun.com http://blog.youkuaiyun.com/pendle/article/details/6574445
这里唯一想说明的一点就是,使用虚函数继承时,当继承类被强转成基类后调用虚函数,调用的还是继承类的虚函数。而重载方式的继承类被强转成基类再调用重载函数,则调用的是基类的函数。废话不多说,上代码:
- #include <iostream>
- using namespace std;
- class A {
- public:
- virtual void fun() { cout << "A::fun" << endl; }
- };
- class AP : A
- {
- public:
- virtual void fun() { cout << "AP:fun" << endl; }
- };
- class B {
- public:
- void fun() { cout << "B:fun" << endl; }
- };
- class BP : B
- {
- public:
- void fun() { cout << "BP:fun" << endl; }
- };
-
- int main(int argc, char* argv[])
- {
- A a;
- a.fun();
- AP ap;
- ((A*)&ap)->fun();
- B b;
- b.fun();
- BP bp;
- ((B*)&bp)->fun();
- return 0;
- }
这段代码执行的输出是:
A::fun
AP:fun
B:fun
B:fun
通过汇编分析主要的代码片段如下:
- fun_A__fun();
- fun_GetAPFuns(&p_fun_addr);
- (*(void (__cdecl **)(int *))p_fun_addr)(&p_fun_addr);
- fun_B__fun();
- fun_B__fun();
其中fun_GetAPFuns函数,就是获取AP实例被强转后的函数表地址,函数定义如下:
- _DWORD *__cdecl fun_GetAPFuns(_DWORD *p_fun_addr)
- {
- _DWORD *result;
- fun_GetAFuns(p_fun_addr);
- result = p_fun_addr;
- *p_fun_addr = &tag_AP_Funs;
- return result;
- }
- _DWORD *__cdecl fun_GetAFuns(_DWORD *p_fun_addr)
- {
- _DWORD *result;
- result = p_fun_addr;
- *p_fun_addr = &tag_A_Funs;
- return result;
- }
不难看出,针对((A*)&ap)->fun(); 这行代码调用,实际上是先获取了基类的函数表,然后又被继承类的函数表覆盖了。因此输出结果才会是AP:fun。
而对于直接重载继承的经过强转调用,在编译时就直接替换成基类的函数调用了。