C++ 虚函数在基类与派生类对象间的表现及其分析

来源:互联网 发布:lazada销量数据分析 编辑:程序博客网 时间:2024/05/17 09:01

转载地址:http://www.cnblogs.com/Romi/archive/2013/09/18/3329132.html

近来看了侯捷的《深入浅出MFC》,读到C++重要性质中的虚函数与多态那部分内容时,顿时有了疑惑。因为书中说了这么一句:使用“基类之指针”指向“派生类之对象”,由该指针只能调用基类所定义的函数,如果要让基类的指针使用派生类中定义的函数,就将该函数定义为虚函数

 但在“Object slicing与虚函数”这一小节给出了一个及其经典的例子,它指出,在向上(即向基类)强制转型时,会造成对象内容的被切割

 下面用示例进行说明:

复制代码
 1 #include "stdafx.h"   2 #include <iostream>   3 using namespace std;   4    5 class A   6 {   7 public:   8     virtual void fn(){cout<<"A fn"<<endl;}   9 };  10   11 class B: public A  12 {  13 public:  14     virtual void fn(){cout<<"B fn"<<endl;}  15 };  16   17 int main(int argc, char* argv[])  18 {  19     B b1;  20     A a1=(A)b1;  21     A * a2=(A*)&b1;  22     a1.fn();  23     a2->fn();  24     return 0;  25 }  
复制代码

 结果如下:

通过调试分析其内存模型如下:

可知,通过A  a1=(A)b1传值时,对象中指向虚函数表的指针__vfptr值不同,但是通过A *a2=(A*)&b1传址操作时,对象中指向虚函数表的指针__vfptr值是相同的,调用的是类B对象的虚函数表中虚函数fn()。注意,对象调用的是哪个类的虚函数就要看类对象的虚函数表中的函数是哪一个。这句话也好理解,a1虚函数表中fn()是A::fn(),a2虚函数表中fn()是B::fn(),所以出现以上结果。

在如下包含父类的父类的继承中:

复制代码
 1 class A 2 { 3 public: 4 virtual void fn(){cout<<"A fn"<<endl;} 5 }; 6  7 class B: public A 8 { 9 public:10 virtual void fn(){cout<<"B fn"<<endl;}11 };12 13 class C: public B14 {15 public:16 };17 C c;18 A a1=(A)c;19 A * a2=(A*)&c;20 a1.fn();21 a2->fn();
复制代码

 这时,a1虚函数表中fn()为A::fn(),a2虚函数表中fn()为B::fn(),因为类C对象的虚函数表中fn()为B::fn(),a2中指向虚函数表的指针值与类C对象指向虚函数表的指针值相同。

侯捷的书中有句话是这么对它进行解释的:由于(A)b1.fn()是传值而非传地址操作,编译器以所谓的拷贝构造函数把A对象内容复制了一份,使得b1的虚函数表内容与A对象的虚函数表内容相同

看来,得多读圣贤书,读懂读透啊!

0 0