#include <iostream>
#include <stdio.h>
class Base
{
public:
int x;
int y;
virtual void function_1()
{
printf("function_1...\n");
}
virtual void function_2()
{
printf("function_2...\n");
}
};
int main(int argc, char ** argv)
{
Base base;
Base *pb;
printf("sizeof = %ld\n", sizeof(class Base)); /* 4 */
printf("base address is 0x%x.\n", &base); // this 指针,是堆栈里面的地址。虚表的地址不是this指针,是this指针的前四个字节。
printf("base virtual table address is:0x%x\n", *(int*)&base); // 虚表地址。取this指针的前4个字节。*(char*)&base为取一个字节。
typedef void(*pfunction)(void);
pfunction pf;
int temp = *((int*)(*(int*)&base) + 0); // 取地址表里面的第一个值
// *(int*)&base) 是虚表地址
// (int*) 转换成一个int*类型。
// *((int*)(*(int*)&base) + 0), 加的是0,即取第一个4字节值。
pf = (pfunction)*((int*)(*(int*)&base) + 0); // 或这样,取地址表里面的第一个值
pf(); // function_1
pf = (pfunction)*((int*)(*(int*)&base) + 1); // 取第二个4字节值
pf(); // function_2
for (int i = 0; i < 2; i++) {
pf = (pfunction)*((int*)(*(int*)&base) + i);
pf();
}
}
#if 0
1.类对象的首地址里面存的第一个4字节才是虚表的地址。即this指针里面存的第一个4字节就是虚表的地址。
2.虚表的地址不是 this 指针,是 this 指针的前四个字节。
3.虚表的个数是编译的时候确定的,有几个 virtual 存几个。
int main(int argc, char ** argv)
{
8048670: 55 push %ebp
8048671: 89 e5 mov %esp,%ebp
8048673: 83 e4 f0 and $0xfffffff0,%esp
8048676: 83 ec 30 sub $0x30,%esp
Base base;
8048679: 8d 44 24 18 lea 0x18(%esp),%eax
804867d: 89 04 24 mov %eax,(%esp)
8048680: e8 1d 01 00 00 call 80487a2 <_ZN4BaseC1Ev>
Base *pb;
printf("base address is %x.\n", &base); // this 指针,是堆栈里面的地址。虚表的地址不是this指针,是this指针的前四个字节。
8048685: 8d 44 24 18 lea 0x18(%esp),%eax
8048689: 89 44 24 04 mov %eax,0x4(%esp)
804868d: c7 04 24 60 88 04 08 movl $0x8048860,(%esp)
8048694: e8 a7 fe ff ff call 8048540 <printf@plt>
printf("base virtual table address is:%x\n", *(int*)&base); // 虚表地址。取this指针的前4个字节。*(char*)&base为取一个字节。
8048699: 8d 44 24 18 lea 0x18(%esp),%eax
804869d: 8b 00 mov (%eax),%eax
804869f: 89 44 24 04 mov %eax,0x4(%esp)
80486a3: c7 04 24 78 88 04 08 movl $0x8048878,(%esp)
80486aa: e8 91 fe ff ff call 8048540 <printf@plt>
typedef void(*pfunction)(void);
pfunction pf;
int temp = *((int*)(*(int*)&base) + 0); // 取地址表里面的第一个值
80486af: 8d 44 24 18 lea 0x18(%esp),%eax
80486b3: 8b 00 mov (%eax),%eax
80486b5: 8b 00 mov (%eax),%eax
80486b7: 89 44 24 28 mov %eax,0x28(%esp)
// *(int*)&base) 是虚表地址
// (int*) 转换成一个int*类型。
// *((int*)(*(int*)&base) + 0), 加的是0,即取第一个4字节值。
pf = (pfunction)*((int*)(*(int*)&base) + 0); // 或这样,取地址表里面的第一个值
80486bb: 8d 44 24 18 lea 0x18(%esp),%eax
80486bf: 8b 00 mov (%eax),%eax
80486c1: 8b 00 mov (%eax),%eax
80486c3: 89 44 24 24 mov %eax,0x24(%esp)
pf(); // function_1
80486c7: 8b 44 24 24 mov 0x24(%esp),%eax
80486cb: ff d0 call *%eax
pf = (pfunction)*((int*)(*(int*)&base) + 1); // 取第二个4字节值
80486cd: 8d 44 24 18 lea 0x18(%esp),%eax
80486d1: 8b 00 mov (%eax),%eax
80486d3: 83 c0 04 add $0x4,%eax
80486d6: 8b 00 mov (%eax),%eax
80486d8: 89 44 24 24 mov %eax,0x24(%esp)
pf(); // function_2
80486dc: 8b 44 24 24 mov 0x24(%esp),%eax
80486e0: ff d0 call *%eax
for (int i = 0; i < 2; i++) {
80486e2: c7 44 24 2c 00 00 00 movl $0x0,0x2c(%esp)
80486e9: 00
80486ea: eb 24 jmp 8048710 <main+0xa0>
pf = (pfunction)*((int*)(*(int*)&base) + i);
80486ec: 8b 44 24 2c mov 0x2c(%esp),%eax
80486f0: 8d 14 85 00 00 00 00 lea 0x0(,%eax,4),%edx
80486f7: 8d 44 24 18 lea 0x18(%esp),%eax
80486fb: 8b 00 mov (%eax),%eax
80486fd: 01 d0 add %edx,%eax
80486ff: 8b 00 mov (%eax),%eax
8048701: 89 44 24 24 mov %eax,0x24(%esp)
pf();
8048705: 8b 44 24 24 mov 0x24(%esp),%eax
8048709: ff d0 call *%eax
pf(); // function_1
pf = (pfunction)*((int*)(*(int*)&base) + 1); // 取第二个4字节值
pf(); // function_2
for (int i = 0; i < 2; i++) {
804870b: 83 44 24 2c 01 addl $0x1,0x2c(%esp)
8048710: 83 7c 24 2c 01 cmpl $0x1,0x2c(%esp)
8048715: 7e d5 jle 80486ec <main+0x7c>
pf = (pfunction)*((int*)(*(int*)&base) + i);
pf();
}
}
8048717: b8 00 00 00 00 mov $0x0,%eax
804871c: c9 leave
804871d: c3 ret
#endif