虚函数

来源:互联网 发布:网络高利贷曝光吧 编辑:程序博客网 时间:2024/06/05 07:18

先粘一段别人的解释

虚函数是在类中被声明为virtual的成员函数,当编译器看到通过指针或引用调用此类函数时,对其执行晚绑定,即通过指针(或引用)指向的类的类型信息来决定该函数是哪个类的。通常此类指针或引用都声明为基类的,它可以指向基类或派生类的对象。
 多态指同一个方法根据其所属的不同对象可以有不同的行为(根据自己理解,不知这么说是否严谨)。

 举个例子说明虚函数、多态、早绑定和晚绑定:
  李氏两兄妹(哥哥和妹妹)参加姓氏运动会(不同姓氏组队参加),哥哥男子项目比赛,妹妹参加女子项目比赛,开幕式有一个参赛队伍代表发言仪式,兄妹俩都想 去露露脸,可只能一人去,最终他们决定到时抓阄决定,而组委会也不反对,它才不关心是哥哥还是妹妹来发言,只要派一个姓李的来说两句话就行。运动会如期举 行,妹妹抓阄获得代表李家发言的机会,哥哥参加了男子项目比赛,妹妹参加了女子项目比赛。比赛结果就不是我们关心的了。
 现在让我们来做个类比(只讨论与运动会相关的话题):
 (1)类的设计:
  李氏兄妹属于李氏家族,李氏是基类(这里还是抽象的纯基类),李氏又派生出两个子类(李氏男和李氏女),李氏男会所有男子项目的比赛(李氏男的成员函 数),李氏女会所有女子项目的比赛(李氏女的成员函数)。姓李的人都会发言(基类虚函数),李氏男和李氏女继承自李氏当然也会发言,只是男女说话声音不一 样,内容也会又差异,给人感觉不同(李氏男和李氏女分别重新定义发言这个虚函数)。李氏两兄妹就是李氏男和李氏女两个类的实体。
 (2)程序设计:
 李氏兄妹填写参赛报名表。
 (3)编译:
  李氏兄妹的参赛报名表被上交给组委会(编译器),哥哥和妹妹分别参加男子和女子的比赛,组委会一看就明白了(早绑定),只是发言人选不明确,组委会看到报 名表上写的是“李家代表”(基类指针),组委会不能确定到底是谁,就做了个备注:如果是男的,就是哥哥李某某;如果是女的,就是妹妹李某某(晚绑定)。组 委会做好其它准备工作后,就等运动会开始了(编译完毕)。
 (4)程序运行:
 运动会开始了(程序开始运行),开幕式上我们听到了李家妹妹的发言,如果是哥哥运气好抓阄胜出,我们将听到哥哥的发言(多态)。然后就是看到兄妹俩参加比赛了。。。

 但愿这个比喻说清楚了虚函数、多态、早绑定和晚绑定的概念和它们之间的关系。再说一下,早绑定指编译器在编译期间即知道对象的具体类型并确定此对象调用成员函数的确切地址;而晚绑定是根据指针所指对象的类型信息得到类的虚函数表指针进而确定调用成员函数的确切地址。
  

 2、揭密晚绑定的秘密

 编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟。

  编译器对每个包含虚函数的类创建一个表(称为V TA B L E)。在V TA B L E中,编译器放置特定类的虚函数地址。在每个带有虚函数的类 中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E。通过基类指针做虚函数调 用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。为每个类设置V TA B L E、初始化V P T R、为虚函数调用插入代码,所有这些都是自动发生的,所以我们不必担心这些。利用虚函数, 这个对象的合适的函数就能被调用,哪怕在编译器还不知道这个对象的特定类型的情况下。(《C++编程思想》

————这段话红色加粗部分似乎有点问题,我个人的理解看后面的总结。

只看四个程序的运行结果

#include <iostream>using namespace std;class A{public:virtual void p()   {   cout << "A" << endl;   }};class B : public A{public: virtual void p()   { cout << "B" << endl;   }};int main(){A * a = new A;A * b = new B;//a->p();b->p();delete a;delete b;system("pause");return 0;}
结果是A

            B

#include <iostream>using namespace std;class A{public:virtual void p()   {   cout << "A" << endl;   }};class B : public A{public: virtual void p()   { cout << "B" << endl;   }};int main(){A * a = new A;B * b = new B;//a->p();b->p();delete a;delete b;system("pause");return 0;}

结果是A

            B

#include <iostream>using namespace std;class A{public:void p()   {   cout << "A" << endl;   }};class B : public A{public:void p()   { cout << "B" << endl;   }};int main(){A * a = new A;A * b = new B;//a->p();b->p();delete a;delete b;system("pause");return 0;}

结果是A

            A


#include <iostream>using namespace std;class A{public:void p()   {   cout << "A" << endl;   }};class B : public A{public:void p()   { cout << "B" << endl;   }};int main(){A * a = new A;B * b = new B;//a->p();b->p();delete a;delete b;system("pause");return 0;}

结果是A

            B








0 0