Chinaunix首页 | 论坛 | 博客
  • 博客访问: 355013
  • 博文数量: 43
  • 博客积分: 1493
  • 博客等级: 上尉
  • 技术积分: 660
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-01 10:57
文章分类

全部博文(43)

文章存档

2015年(1)

2013年(1)

2011年(6)

2010年(13)

2009年(13)

2008年(9)

分类: C/C++

2009-04-30 19:37:15

                          C++类分布——实例分析

一:例子代码:

1#include

      2 const char * global_text="aaaa";

      3 class empty

      4 {

      5 virtual void sayHello(){printf("hello world\n");}

      6

      7

      8 };

      9 class Base

     10 {

     11 public:

     12 Base(int i1,char i2,short i3,char i4):i(i1),j(i2),k(i3),l(i4){}

     13 void    print(){printf("hello world\n");};

     14 virtual int work(int i){printf("this is base work %d\n",i);}

     15 virtual void work2(){printf("this is base work2\n");}

     16 virtual void work3(){printf("this is base work3\n");}

     17 static int wangfei;

     18 private:

     19 int i;

     20 char j;

     21 short k;

     22 char l;

     23 };

     24 int Base::wangfei=8888;

     25 int global_data=7777;

     26 class Derive:public Base

     27 {

     28 public:

     29 Derive(int i1,char i2,short i3,char i4):Base(i1,i2,i3,i4){}

     30 int work(int);

     31 static void print(){printf("this is derive print\n");}

     32 virtual void d_work1(){}

     33 };

     34 int Derive::work(int i)

     35 {

     36     printf("this is derive work %d\n",i);

     37     return 10;

     38

     39

     40 }

     41 int main(int argc,char **argv)

     42 {

     43 char *test="hello world\n";

        44 empty e;

     45 printf("the size of e is %d\n",sizeof(e));

     46 printf("sizeof the test is %d\n",sizeof(test));

     47 Derive d(2,'c',3,'d');

     48 Base b(10,'a',20,'b');

     49 b=d;

     50 printf("sizeof b is %d,sizeof d is %d\n",sizeof(b),sizeof(d));

     51 b.work(1);

     52 d.work(1);

     53 Base *pointB=new Derive(4,'e',5,'f');

     54 pointB->work(1);

     55 printf("below will force to invoke\n");

     56 int addr = *((int *)(*(int *)(pointB)));

     57 printf("the addr is %p\n",addr);

     58 int result=0;

     59 int first=*((int *)(pointB)+1);

     60 printf("the first is %d\n",first);

     61 char second=*(char *)((int *)(pointB)+2);

     62 printf("the second is %c\n",second);

     63 short third=*(short *)((int *)(pointB)+3);

     64 printf("the third is %d\n",third);

     65

     66 __asm__(

     67         //"mov %0,%%ecx\n\tpush $2\n\tcall *%1"::"m"(pointB),"m"(addr)

     68         "push $222\n\tpush %0\n\tcall *%1"::"m"(pointB),"m"(addr)

     69 );

     70 printf("after asm\n");

     71     //call addr;

     72

     73 return 0;

     74 }

     这个例子的主要目的是为了说明各类型的成员在类中如何分配,vtable在类中的位置以及多态的内部如何实现。

二:分析:

假设输出为这个示例代码最后被编译成a.out的可执行文件。

1,  objdump –C -t -j .data a.out|grep data

输出信息为:

08048940 l    d  .rodata        00000000

08049d00 l    d  .data  00000000

08049d08 l     O .data  00000000              p.0

08048aa4  w    O .rodata        00000008              typeinfo for empty

08048940 g     O .rodata        00000004              _fp_hw

08049d10 g     O .data  00000004              Base::wangfei

08049d04 g     O .data  00000000              .hidden __dso_handle

08049d14 g     O .data  00000004              global_data

08048a68  w    O .rodata        00000018              vtable for Derive

08048aac  w    O .rodata        00000008              typeinfo for Base

08048a80  w    O .rodata        00000014              vtable for Base

08049d00  w      .data  00000000              data_start

08049d0c g     O .data  00000004              global_text

08048ac0  w    O .rodata        00000007              typeinfo name for empty

08048acd  w    O .rodata        00000008              typeinfo name for Derive

08048ac7  w    O .rodata        00000006              typeinfo name for Base

08049d18 g       *ABS*  00000000              _edata

08048a98  w    O .rodata        0000000c              vtable for empty

08048944 g     O .rodata        00000004              _IO_stdin_used

08049d00 g       .data  00000000              __data_start

08048ab4  w    O .rodata        0000000c              typeinfo for Derive

 

红色的三行说明了一些信息:

A,类的静态成员变量不是在类里面分配的,这也正好符号了我们一般的逻辑,因为我们很可能在没有一个类实例的情况下访问它这个成员(如果是public的);

B,全局变量也是在data段里面。

C,类的函数不是在类里分配的,而是联合类名和参数变成了另外一个函数名,调用的时候传相应的类的this指针进去。

D,拥有虚函数的类会多出四个字节用于存放指向vtable的指针。

E,当发生子类指针向父类指针赋值的时候,会发生截断,对应于父类的大小的区域被分给父类,其余被截掉,但是因为vtable的指针是放在类的开始的,所以,子类的虚函数指针被赋给了父类,于是调用的时候就调用了子类的函数,这就是虚函数的内部实现!!!

 

2,  修改第56行,如果改成:

int addr = *((int *)(*(int *)(pointB))+1or 2 or 3);这样就可以分别调用第一第二个虚函数。

从这里可以看出,虚函数的位置在拥有虚函数的类的第一个位置。

3,  596163行可以看出,

类的数据的排列是按照它的申明顺序的。

4,  .rodata可以看出,vtable的内容本身是放在rodata段里面的也就是说是不可修改的。

5,  如果把43行:

char *test="hello world\n";

然后*test=”good bye”;

你会看到编译的出错信息!

原因在于”hello world\n”以及所有这些待打印出来的字符串都是放在readonlydata 段的。

要修改一个只的区域的内容当然会错了。

但是test这个变量本身你是看不到的在符号表里面,因为它会被分配在堆里面,并且是 在运行时被分配的。

但是你能看到global_text的符号,它本身是被分配在data段里面的,但它所指向的内容也是在只读段里面的。

可以通过objdump –C –d –j .rodata a.out来查看所有只读段里面的内容。

注意我上面说的段是指section不对应操作系统里面的segment

你可以用readelf –l a.out来查看具体的section  segment的对应关系。

一般rodata段都会被放在text segment.

 

阅读(1898) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~