如果您无法下载资料,请参考说明:
1、部分资料下载需要金币,请确保您的账户上有足够的金币
2、已购买过的文档,再次下载不重复扣费
3、资料包下载后请先用软件解压,在使用对应软件打开
C++编程之理解虚函数本文目的了解虚函数的定义、应用场合、内部实现机制以及注意事项。什么是虚函数?缺省情况下,类的成员函数是非虚拟的(nonvirtual)。当一个成员函数为非虚拟的时候,通过一个类对象(指针或引用)而被调用的该成员函数,就是该类对象的静态类型中定义的成员函数。当类的成员函数被virtual关键字修饰时,该函数就是虚函数。当成员函数是虚函数时,通过一个类对象(指针或引用)而被调用的该成员函数,是在该类对象的动态类型中被定义的成员函数。普通函数虚函数class类名{public:函数说明;};class类名{public:virtual函数说明;};对于动态类型的理解:虚函数允许派生类取代基类所提供的实现。为什么使用虚函数?C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。简单的例子://基类——AclassA{public:virtualvoiddescribe(){cout<<"ThisisA."<<endl;}};//类B——派生于基类AclassB:publicA{public:virtualvoiddescribe(){cout<<"ThisisB."<<endl;}};intmain(intargc,char*argv[]){A*p=newA();p->describe();deletep;p=newB();p->describe();deletep;return0;}输出结果:什么时候使用虚函数?在实际开发过程中,当我们使用一些类库或框架时,这些类库和框架是事先定义或设计好的,我们不能直接修改类库或框架的代码,这样我们只能派生类库或框架中的类来覆盖一些成员函数以实现我们的功能,但这些成员函数是由类库或框架来调用的,这种情况下,使用虚函数是很好的解决办法。追根究底——虚函数的实现机制虚函数表C++规定了虚函数的行为,但将实现方法留给了编译器作者。不需要知道实现方法就可以使用虚函数,但了解虚函数的工作原理有助于更好地理解概念。例子:计算类的大小是多少?classA{public:voiddescribe(){cout<<"ThisisA."<<endl;}};intmain(intargc,char*argv[]){Aa;cout<<"求a对象的大小:"<<sizeof(a)<<endl;return0;}输出结果:例子:计算类的大小是多少?classA{public:voiddescribe(){cout<<"ThisisA."<<endl;}//虚函数virtualvoidfunc1(){cout<<"Callfun1inClassB."<<endl;}};intmain(intargc,char*argv[]){Aa;cout<<"求a对象的大小:"<<sizeof(a)<<endl;return0;}输出结果:对C++了解的人都应该知道虚函数(VirtualFunction)是通过一张虚函数表(VirtualTable)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。通常,编译器处理虚函数的方法是:给每个对象添加一个隐藏成员。隐藏成员中包含了一个指向函数地址数组的指针。这种数组成为虚函数表(virtualfunctiontable,vtbl)。虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址;如果派生类没有重新定义虚函数,该vtbl将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也将被添加到vtbl中。注意,无论类中包含的虚函数是1个还是多个,都只需要在对象中添加1个地址成员,只是表的大小不同而已。这里我们着重看一下这张虚函数表。C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并