C++虚函数
C++
在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。--(来至百度百科)
以下是定义的测试模型类:
1 class Base 2 { 3 public: 4 virtual void print() 5 { 6 printf("Base print..\n"); 7 } 8 9 void echo () 10 { 11 printf("Base echo..\n"); 12 } 13 14 void doAction(int count) 15 { 16 printf("Base doAction:%d..\n",count); 17 } 18 ~ Base() 19 { 20 printf("Base: ~Base\n"); 21 } 22 }; 23 24 class A:public Base 25 { 26 public: 27 void print() 28 { 29 printf("A print..\n"); 30 } 31 32 void echo () 33 { 34 printf("A echo..\n"); 35 } 36 37 void doAction(int count) 38 { 39 printf("A doAction:%d..\n",count); 40 } 41 ~ A() 42 { 43 printf("A: ~A\n"); 44 } 45 };
下面通过代码实例对多
1 int main(int argc, const char * argv[]) { 2 // insert code here... 3 4 A var; 5 Base *p = &var; 6 A *q = &var; 7 8 p->print(); 9 q->print(); 10 p->echo(); 11 q->echo(); 12 13 return 0; 14 }
输出如下:
1 A print.. 2 A print.. 3 Base echo.. 4 A echo..
父类Base中print()设置为虚函数,子类A同名同参数以及返回值的print()也默认为虚函数(virtaul void print(),这一步编译器自动帮我们做了),编译器为A和Base 分别建立了一张虚函数表,在函数调用时通过查这个表来获得函数的代码段地址,进而执行不同的功能。而两个类中的echo()是通过指针获得相对地址来直接执行相应的代码。
C++默认的“隐藏”功能,使得父类Base中的echo()被隐藏,子类A中echo()得到执行,请注意有别于override
另:析构函数往往也被定义为virtual
以上呈现的是将子类强制转换成父类的情况,现在就看看将父类强制转换子类的情况。
1 Base b; 2 A *a = (A *)&b; 3 4 a->print();//输出Base print.. 5 a->echo();//输出A echo.. 6 7 //对比 8 A a0; 9 Base *b0 = &a0; 10 b0->print();//输出A print.. 11 b0->echo();//输出Base echo..
这个输出结果可能跟预期的不一样,尤其是print()的输出。这就需要应用本文已开始提到的,虚函数的访问是以查虚表的形式来运行的,指针类型的转换,并不影响虚表指针。
虚表的创建和虚表指针的初始化在构造函数中进行,然而本例中只调用了父类的构造函数,即只初始化父类的虚表,指针类型转化并未调用子类的构造函数。