虚函数

来源:互联网 发布:北京圣思园java视频 编辑:程序博客网 时间:2024/06/05 07:19

一、虚函数

虚函数是在基类中声明,在继承类中重新定义(函数返回值、参数、函数名均相同)。

假如在基类中定义了一个虚函数,那么当继承该基类时重新定义该函数的话,那么访问情形是:定义一个基类指针,如果该指针指向基类对象,那么通过指针来访问该函数时,调用的是基类的函数,假如该指针指向继承类的话那么指针调用的这个函数就是继承类中的函数。这个就是实现了覆盖。当然,假如你如果定义一个基类对象那么通过基类对象来访问该函数时,调用的就是基类的函数,如果定义一个继承类对象,那么通过该对象就是调用继承类中的函数。

二、虚函数与重载的区别

函数重载处理的是同一层次上的同名问题,而虚函数处理的是不同派生层次上的同名函数问题,前者是横向重载,后者是纵向重载,但与重载不同的是:同一个类族(即继承类继承基类)的首部是相同的(即函数返回值、参数、函数名均相同),而函数重载时函数的首部不同的(参数个数或者类型不同)。

三、通过对象访问虚函数,这个是在编译时就已经确定的,这个属于静态关联,而如果通过指针来访问不同类中的虚函数的时候,此时称为动态关联,因为这个是在运行的时候确定的。

四、在什么情况下声明虚函数

1、首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,那么可以声明该函数为虚函数。

2、如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。不要仅仅考虑到要作为基类中的所有成员函数都声明为虚函数。

注意:使用虚函数,系统要有一定的开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址。系统在进行动态关联时的开销是很少的,因此,多态性是高效的。

 

补充:每一个具有虚函数的类都叫做多态类,这个虚函数或者是从基类继承来的,或者是自己增加的。C++必须为每一个多态类至少创建一个虚函数表(vtable),它其实就是一个函数指针数组,其中存放着这个类所有的虚函数的地址及该类的类型的信息,其中也包括那些继承但未改写的虚函数。每一个多态对象都有一个隐含的指针成员,它指向所属类型的vtable,这就是vptr。显然,类型信息应该保存在vtable中固定的位置上,否则就无法实现统一的检索操作。

实质:程序中通过基类指针或引用对虚函数的调用语句都会被编译器改写成下面这种形式:

(*(p->_vptr[slotNum]))(p,arg-list)   //指针当做数组来用,最后改写为指针运算

其中,p是基类类型的指针,vptr是p指向的对象的隐含指针,而slotNum就是调用的虚函数在vtable中的编号,这个数组元素的索引号在编译时就确定下来了,并且不会随着派生层次的增加而改变。

分析:当基类指针指向基类对象时,那么此时基类的对象有个指向它的vptr指针,那么通过基类指针去查找vtable中的函数就是基类中的函数(虚),而如果基类指针指向派生对象,那么此时有一个vptr指针指向派生对象,由(*(p->_vptr[slotNum]))(p,arg-list) 可知基类指针指向了派生类中的vtable表中的函数了(虚函数且该虚函数将基类的虚函数覆盖了)。

原创粉丝点击