当前位置:编程学习 > C/C++ >>

关于C++ 虚函数表的一些问题(G++)

 
#include <cstdio>
#include <iostream>
#include <typeinfo>
using namespace std;
class Point
{
public:
    Point()
    {
        cout<<"Point constructor"<<endl;
    }
 
    virtual void func_hs()
    {
        cout<<"Point::func_hs"<<endl;
        printf("the address of this --func_hs:%p\n",&Point::func_hs);
    }
    virtual void  func_zzy()
    {
        cout<<"Point::func_zzy"<<endl;
        printf("the address of this --func_zzy:%p\n",&Point::func_zzy);
    }

    static void print()
    {
        //相对地址,在虚表指针之后.0x4 0x8 0xc --------->point to member
        printf("&Point::x=%p\n&Point::y=%p\n&Point::z=%p\n",
               &Point::x,&Point::y,&Point::z);
    }

    void printThis()
    {
        //float *
        printf("&this->x=%p\n&this->y=%p\n&this->z=%p\n",
               &this->x,&this->y,&this->z);
    }

    void printVt()
    {
        printf("the address of object,this:%p\nthe address of vt:%p\n",
               this,(void*)*(int*)this);
    }
    void callVtFuncs(int num=2)
    {
        cout<<endl<<endl;
       
        typedef void (*Funp)(void);
       
       
        for(int i=0;i<num;i++)
        {
            Funp funp=(Funp)*((int*)*(int*)this+i);
            printf("%p\n",((int*)*(int*)this+i));
            printf("Point::callVtFuncs=>address of this fun:%p\n",funp);
            if(i==2||i==3)
            {
                continue;
            }
            funp();
        }
    }

    void printVirtualFunAddress()
    {
        cout<<endl<<endl;
           printf("func_hs:%p\nfunc_zzy:%p\nfunc_zzzy:%p\n",
              &Point::func_hs,&Point::func_zzy,
              &Point::func_zzzy);
        printf("%p\n",&Point::func_zzzy);
       
    }
    virtual ~Point()
    {
        // printf("%p\n",&Point::~Point);
        cout<<"Point destructor"<<endl;
    }
    virtual void  func_zzzy()
    {
        cout<<"Point::func_zzzy"<<endl;
        printf("the address of this --func_zzzy:%p\n",&Point::func_zzzy);
    }

protected:
    float x,y,z;
};

   
int main(int argc, char *argv[])
{
    Point point;
    Point::print();
    point.printThis();
    point.printVt();
    point.callVtFuncs(5);
    point.printVirtualFunAddress();
    printf("sizeof func:%u\n",sizeof(&main));
    printf("%p\n",&main);
   
    printf("sizeof memfunc:%u\n",sizeof(&Point::printVirtualFunAddress));
    printf("%p\n",&Point::printVirtualFunAddress);
   
    printf("%p\n",&Point::func_zzzy);

    printf("sizeof virtmemfunc:%u\n",sizeof(&Point::func_zzzy));
    cout<<typeid(point).name()<<endl;
   
    return 0;
}


Point类里面包括virtual desctructor共有4个virtual functions.
输出结果如下:

Point constructor
&Point::x=0x4
&Point::y=0x8
&Point::z=0xc
&this->x=0xbffff624
&this->y=0xbffff628
&this->z=0xbffff62c
the address of object,this:0xbffff620
the address of vt:0x8048fc0


0x8048fc0
Point::callVtFuncs=>address of this fun:0x8048a12
Point::func_hs
the address of this --func_hs:0x1
0x8048fc4
Point::callVtFuncs=>address of this fun:0x8048a64
Point::func_zzy
the address of this --func_zzy:0x5
0x8048fc8
Point::callVtFuncs=>address of this fun:0x8048c8e
0x8048fcc
Point::callVtFuncs=>address of this fun:0x8048cda
0x8048fd0
Point::callVtFuncs=>address of this fun:0x8048cf8
Point::func_zzzy
the address of this --func_zzzy:0x11


func_hs:0x1
func_zzy:(nil)
func_zzzy:0x5
0x11
sizeof func:4
0x804880c
sizeof memfunc:8
0x8048bdc
0x11
sizeof virtmemfunc:8

data member那一块比较简单,没有太大的问题。主要是virtual table这块比较复杂 。第一个小问题就是
顺序的问题。实验证明在vtable中虚函数指针的顺序是按照声明时的顺序放置的。不管virtual desctructor
在哪个位置,都会占据两个slot,即有两个virtual desctructor.至于为什么会有两个,具体我也不是太清楚,
后面在讨论。
我第一个有一个有疑问的地方就是关于typeinfo的问题。记得《Inside the c++ object model》中,Lippman
提到的对象模型中,将typeinfo放置在vtable的第一个slot中,而根据上面例子来看,第一个slot就是所声明
的第一个virtual function.那么typeinfo存在何处?

vtable 的首地址是0x8048fc0,而从0x8048fb0开始的内存地址信息如下:

(gdb) x/16a 0x8048fb0
0x8048fb0:      0x75253a63&nb

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,