码迷,mamicode.com
首页 > 其他好文 > 详细

单继承下的虚表布局

时间:2015-05-21 18:42:25      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:

在C++中,多态表示 “以一个公有基类的指针或引用,寻址出一个派生类对象” 。

假如有调用 ptr->get_c() ,其中ptr是基类指针,get_c()是一个虚函数。要在执行期能正确调用get_c()的实例,我们需要知道:

     1.ptr所指对象的真正类型,以便我们选择正确的get_c()实例。

     2.get_c()实例的位置,以便我们能够调用他。

在实现上,编译时期会构建出来一张虚表,表格中有程序的虚函数的执行期地址。

              为了找到这个表格,每一个类对象被安插一个由编译器产生的指针,指向虚表。

              为了找到函数地址,每一个虚函数被指派一个表格索引值。

 

如果有代码例子:

class A
{
protected:
    int a;
public:
    A(const int a) :a(a){}
    virtual ~A();
    virtual int pure_v() = 0; //纯虚函数
    virtual int get_b(){ return 0; }
    virtual int get_c(){ return 0; }
};
class B :public A
{
protected:
    int b;
public:
    B(int a = 0, int b = 0):A(a),b(b){}
    ~B();
    int pure_v();
    int get_b(){ return b; }
};
class C :public B
{
protected:
    int c;
public:
    C(int a = 0, int b = 0, int c = 0) :B(a, b), c(c){}
    ~C();
    int pure_v();
    int get_c(){ return c; }
};

一个类只会有一张虚表。每个表内含其对应类对象中三类虚函数,这三类包括:

    1.这一类所定义的虚函数实例或改写自基类的虚函数实例。如例子中Calss B中的get_b()。

    2.继承自基类的已被改写过的函数实例。如例子中Calss C的虚表中会有get_b(),在C中不改写,而在B中已被改写过。

    3.一个纯虚函数的实例。如Class B中的pure_v()。

接下来我们看类A,B,C的虚表布局。

对于A a; 布局如下:(博主是用visio画的,有点丑- -)

技术分享

_vptr是编译时期产生的虚表指针。

slot 0通常是指出每个类所关联的type_info object(用以支持RTTI)。

A的虚析构被指派为solt 1。纯虚函数被指派为solt 2,但A中的纯虚函数没有定义,如果意外调用了此函数,通常的操作是结束这个程序。

get_b()被指派slot ,get_c()被指派slot 4。

对于B:A b; 布局如下:

技术分享

B的虚表中在solt 1指出析构函数。A中的纯虚函数有了定义,所以在slot 2指出pure_()。

自己的get_b()函数实例地址放在solt 3。继承自A的get_c()函数实例地址放在solt 4。

对于C:B c; 布局如下:

技术分享

solt 1放置析构函数地址,solt 2放置pure_v()函数地址,solt 3放置继承自B的get_b()的函数地址,solt 4放置自己的get_c()函数地址。

 

现在再来看调用ptr->get_c();

*在每次调用get_c()时,我们并不知道ptr所指对象的真正类型。但是我知道通过ptr可以存取到该对象的虚表。

*虽然我不知道哪一个get_c()函数实例会被调用,但是我知道每一个get_c()的函数实例地址都被放在solt 4中。

通过这些信息,编译器可以把调用改写为:

                                                   (ptr->_vptr[4])(ptr);  

从而在执行期调用正确的函数实例。

单继承下的虚表布局

标签:

原文地址:http://www.cnblogs.com/zjc0202/p/4520162.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!