发布日期:2016-01-05 17:20 来源: 标签: 编程语言 开发语言 C++入门教程 C++虚函数调用原理
虚函数是C++中一个重要的概念,搞清楚这个概念对于理解C++运行的内在机制有一定的帮助,下面我们就做一下具体讲解,希望大家多多支持中国站长网络学院。
虚函数是C++中一个重要的概念,搞清楚这个概念对于理解C++运行的内在机制有一定的帮助。下面通过一个例子来总结一下C++中虚函数的调用原理。
示例代码:
C++代码  
    #include <iostream>  
    #include <cstdlib>  
    using namespace std;
    class A  
    {  
      public:  
             void set(int i,int j)  
             {  
                  x=i;  
                  y=j;       
             }      
               
             virtual int get()  
             {  
                 return x+y;          
             }  
      private:  
              int x;  
              int y;  
    };  
    class B:public A  
    {  
      public:  
             void set(int i,int j)  
             {  
                  x=i;  
                  y=j;      
             } 
             int get()  
             {  
                 return x+y;      
             }  
      private:  
              int x;  
              int y;  
    };  
    int main(int argc,char *args[])  
    {  
        B b;  
        b.set(4,6);  
        B &rb=b;  
        cout<<rb.get()<<endl;  
        A a;  
        a.set(7,8);  
        cout<<a.get()<<endl;  
        A &ra=b;  
        cout<<ra.get()<<endl;  
        system("pause");  
        return EXIT_SUCCESS;      
    } 
对于上述代码,下面是通过基类的引用来调用虚函数时(ra.get())所经历的几个阶段:
1. 开始调用ra.get(),在运行中引用ra可以判断到底指向了哪个对象(基类or派生类)
2. 取得对象的vtable的指针
3. 从vtable那里获得函数入口的偏移量,即得到要调用的函数的指针
4. 根据vtable的地址找到函数,并调用函数
一个函数说明为虚函数,表明在继承的类中重载这个函数时,到调用这个函数时应该确定调用哪个对象的这个函数。这也就是所谓多态的机制,多态使得我们可以通过基类的引用或指针来指明一个对象(包括其派生类的对象),当调用函数时可以自动判断调用的是哪个对象的函数。
C++编译器对普通函数和虚函数有着两种非常不同的处理方式。
对于普通函数处理而言,特定的函数都会映射到特定的代码,无论是编译阶段还是链接阶段, 编译器都可以计算出要处理函数的地址,直接调用即可。
而对于虚函数而言,被调用的函数不仅仅需要依据调用的特定函数,还需要依据调用对象的种类进行判断。通常情况下都是通过一个叫虚函数表(vtable)来实现的。
虚函数表的结构
虚函数表是一个函数指针表,每个表项都指向一个函数。任何一个包含至少一个虚函数的类都会有这样一张表。需要注意的是vtable只包含虚函数的指针,没有函数体。实际上就是一个函数指针的数组。虚函数表既有继承性又有多态性。每个派生类的vtable继承了它各个基类的vtable,如果基类vtable中包含某一项,则它的派生类的vtable中也将包含同样的一项,但是这两项的值可能是不同的。如果派生类重载(override)了该项对应的虚函数,则派生类vtable的该项指向重载后的虚函数。若没有重载的话,则直接沿用基类的值。
特别注意的是,每一个类中仅有唯一的一个vtable,不是每个对象都有一个vtable。但是每个对象都有一个指向所属类的vtable的指针(此类包含虚函数的前提下)。每个对象额外增加了一个指针的大小,通常是4个字节。
此外,还需要注意的是基类和派生类使用的vtable是物理上独立的,即它们具有不同的地址。它们唯一的联系就是,当派生类没有实现基类虚函数的重载时,派生类会将自己vtable中对应函数的地址设定为基类函数的地址。

相关评论

专题信息
    Visual C++是一个功能强大的可视化软件开发工具,是高等院校计算机及相关专业主要核心课程。 本教程对Visual C++ 的应用与开发进行了详细系统的介绍,内容主要包括:Visual C++程序的建立,菜单、工具栏和状态栏的创建,对话框和常用控件,窗口、文档与视图,图形绘制,数据库应用,多媒体技术等。 本教程以案例教学为主,各章节都附有大量的实例,并且操作步骤详细,有利于引导读者更好的消化、理解和实际应用本章节所学的知识内容,希望大家能多多支持中国站长网络学院!