`
YuHuang.Neil
  • 浏览: 181340 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

通过一个实例来分析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中对应函数的地址设定为基类函数的地址。







Reference

1. 《从新手到高手C++全方位学习》 PP.245 系统是如何调用虚函数的
2. http://www.cppblog.com/ElliottZC/archive/2007/07/20/28416.aspx


分享到:
评论

相关推荐

    c++中子类对象不能调用父类中的虚函数

    c++里,指针和引用是很重要的概念,这个程序不仅对指针和引用做了说明、使用,而且对子类不能继承父类虚函数也做了说明。

    实例分析C++的虚表的查看,使用,调用虚函数

    用c++类的实例解析虚函数表,查看虚表的地址,利用虚函数表中的地址调用虚函数实现C++中的多态特性, 此例是解析虚函数中简单易于理解的示例,重要的地方具有详细的注释。亲测可用,若有不清除的地方,可以留言,...

    C++中虚函数的实现机制

    介绍了C++编程语言中的虚函数及其在进行面向对象程序设计中重要性,并且详细阐述了它在...它通过一个vptr和vtable在运行时进行动态绑定,从而能够根据对象类型的不同调用不同的 虚函数;并通过实例测试验证了上述机制.

    C++虚函数表解析

    C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际 子类的成员函数。

    构造函数不能声明为虚函数的原因及分析

    1. 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有...

    C++_虚函数表解析

    C++_虚函数表解析 C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这...

    虚函数表工作原理

    这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

    C++中的虚函数表图解

    C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。

    C++ 虚函数的详解及简单实例

    虚函数是在基类定义,然后子类重写这个函数后,基类的指针指向子类的对象,可以调用这个函数,这个函数同时保留这子类重写的功能。 纯虚函数是可以不用在基类定义,只需要声明就可以了,然后因为是纯虚函数,是不能...

    深入剖析C++虚函数表

    这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

    (转)多重继承下的虚函数表

    这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,VFTable就显得尤为重要了,它就像一个地图一样,指明了实际所应该调用的函数。在C++的标准中提到,...

    使用指针和引用处理虚函数实例

    《Visual C++2012入门经典(第6版)》实例,使用指向基类对象的指针调用虚函数,使用引用处理虚函数

    C++ 虚函数表解析

    C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...

    C++虚函数表实例分析

    多态是C++面向对象程序设计的一个重要特性。以前看到虚函数觉得很神奇,为...当我们通过父类指针来操作一个子类的时候,调用虚函数,都是通过虚函数表+固定的偏移,这样运行期多态便实现了。 在深度《深度》这本书中

    c++语言中虚函数实现多态的原理详解

    多态是c++的特点之一,关于多态,简而言之就是 用父类的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种方法呢,可以让父类的指针具有多种形态,也就是说不需要改动很多的代码就可以让父类这...

    深入解析C++中的虚函数与多态

    对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)和一个指向虚函数表的指针(vptr)来实现的。虚函数表,简称为vtbl,虚函数表表对实现多态起着至关重要

    C++ 多态 虚表 分析 图解 .doc

    C++ 中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技 术可以让父类的指针有“多种形态”,这是一种泛型技术...

Global site tag (gtag.js) - Google Analytics