我理解的C++虚函数表

时间:2014-10-08 17:53:45   收藏:0   阅读:239

今天拜读了陈皓的C++ 虚函数表解析的文章,感觉对C++的继承和多态又有了点认识,这里写下自己的理解。如果哪里不对的,欢迎指正。如果对于C++虚函数表还没了解的话,请先拜读下陈皓的C++ 虚函数表解析的文章,不然我写的可能你看不懂。

以前一直对于c++多态感觉很神奇,从书上看,多态就是在构造子类对象的时候,通过虚函数,利用父类指针,来调用子类真正的函数。这个解释是正确的,但是它是怎么实现的呢,一直再猜想。以前也知道有虚函数表这件事,也没有仔细理解是什么东东。今天仔细读了陈皓的文章,才明白C++多态的原理。这里说说我的理解:

 先附上我写的一段简单代码:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 class Base{
  5 public:
  6     virtual void f() { cout << "Base::f()" << endl;}
  7     virtual void g() { cout << "Base::g()" << endl;}
  8 };
  9 class Derive : public Base {
 10 public:
 11     virtual void f() { cout << "Devive::f()" << endl;}
 12     virtual void f1() { cout << "Devive::f1()" << endl;}
 13     virtual void g1() { cout << "Devive::g1()" << endl;}
 14 };
 15 typedef void (*Fun)(void);
 16 
 17 int main()
 18 {
 19     Fun pFun = NULL;
 20 
 21     Base b;
 22     cout << "virtual table address: " << (int*)(&b) << endl;
 23     cout << "first virtual function address: " << (int*)*(int*)(&b) << endl;
 24     pFun = (Fun)(*(int*)*(int*)(&b));
 25     pFun();
 26     pFun = (Fun)*((int*)*(int*)(&b)+1);
 27     pFun();
 28 
 29     cout << "*********" << endl;
 30 
 31     Derive d;
 32     cout << "virtual table address: " << (int*)(&d) << endl;
 33     cout << "first virtual function address: " << (int*)*(int*)(&d) << endl;
 34     pFun = (Fun)(*(int*)*(int*)(&d));
 35     pFun();
 36     pFun = (Fun)*((int*)*(int*)(&d)+1);
 37     pFun();
 38     pFun = (Fun)*((int*)*(int*)(&d)+2);
 39     pFun();
 40     pFun = (Fun)*((int*)*(int*)(&d)+3);
 41     pFun();
 42 

 

 输出结果:

virtual table address: 0xbfd268f8
first virtual function address: 0x8048b90
Base::f()
Base::g()
*********
virtual table address: 0xbfd268f4
first virtual function address: 0x8048b78
Devive::f()
Base::g()
Devive::f1()
Devive::g1()

理解1:首先你想要实现多态就必须通过虚函数,如果第6行我们改为 void f() { cout << "f" << endl;}, 那么顾名思义这个f()函 数就不会进入虚函数表中,也就没有多态之说了

 

理解2:在32位系统和64位系统下,取得虚函数表里的函数的方法还有所不同,再32位系统下,如程序那样取就行,而在64位系统下,取得第二个函数(Fun)*((int*)*(int*)(&d+2),第三个函数(Fun)*((int*)*(int*)(&d+4)....

 

理解3:对于程序清单里,我们分别输出类 Base和类Derive的v-table的地址和第一个虚函数的地址,我们发现,他们地址根本不一样,所以说,C++会为每一个类都分配一个virtual table

 

理解4:在理解了虚函数表的结构后,我觉得多态的函数调用,是跟子类的虚函数表有关的,可以说是跟子类没有直接关系的(我以前觉得多态函数的调用是先去父类的函数中找这个函数,然后在这个子类中找同样的函数调用它,现在想来真是2到渣的节奏)

附几张图,来说明这个调用关系

说明一下,父类a的函数分别是virtual void f(),virtual void g(),virtual void h()

     子类b的函数分别是virtual void f1(), virtual void g1(), virtual void h1()

     子类c的函数分别是virtual void f(), virtual void g1(), virtual void h1()

类a.只有父类时

 bubuko.com,布布扣

类b.有子类继承,但是没有函数的重载

 bubuko.com,布布扣

类c.有子类继承,有函数重载

 bubuko.com,布布扣

如:我们调用

Derive c;

Base *p_base = &c;

p_base->f();

这里的调用过程是,在类C虚函数表中查找到Base类的f()的地址【虚函数表内函数的存放顺序是,先放父类的虚函数,然后再存放子类的虚函数】,然后在该地址处取得存放的真正的函的地址,即是子类的函数,故调用的是子类的函数

 版权所有,如要转载请说明出处及作者

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!