c++ 虚函数地址

小菩提的尾巴 2012-03-23 05:04:41
最近在看《深度探索C++对象模型》这本书,看到类继承的对象布局那里,就写了如下的代码来玩玩看

#include<stdio.h>
#include<string.h>

class Person
{
public:
Person(char *name, int age);
~Person();
public:
char * GetName() const {return (char*)&this->m_name;}
int GetAge() const {return this->m_age;}
virtual void Say();
protected:
char m_name[20];
int m_age;
};

Person::Person(char *name, int age)
{
strcpy(this->m_name, name);
this->m_age = age;
}

Person::~Person()
{
//
}

void Person::Say()
{
printf("My name is %s, I'm %d this year.\n", this->m_name, this->m_age);
}

//////////////////////////////////////////////////////////////////////////

class Student : public Person
{
public:
Student(char *name, int age, int id);
~Student();
public:
virtual void Say();
protected:
int m_id;
};

Student::Student(char *name, int age, int id)
: Person(name, age)
{
this->m_id = id;
}

Student::~Student()
{

}

void Student::Say()
{
printf("I am a student by the name of %s, I'm %d, my id is %d.\n",
this->m_name, this->m_age, this->m_id);
}

int main()
{
Person pa("pa", 12);
Student s("st", 20, 2008);
Person *ps = &s;

pa.Say();
s.Say();
ps->Say();

printf("&pa:%0x\n", &pa);
printf(" &s:%0x\n", &s);
printf(" ps:%0x\n", ps);

printf("pa.say:%0x\n", pa.Say);
printf(" s.say:%0x\n", s.Say);
printf("ps.say:%0x\n", ps->Say);

return 0;
}

代码输出如下:
My name is pa, I'm 12 this year.
I am a student by the name of st, I'm 20, my id is 2008.
I am a student by the name of st, I'm 20, my id is 2008.
&pa:12ff58
&s:12ff38
ps:12ff38
pa.say:401028
s.say:401028
ps.say:401028
Press any key to continue
关于获取类对象的Say()虚函数地址那种写法,我知道是错的,问题是
printf("pa.say:%0x\n", pa.Say);
printf(" s.say:%0x\n", s.Say);
printf("ps.say:%0x\n", ps->Say);
这几句的输出内容让我很迷惑,究竟它输出的数字401028是不是没有什么意义的,知道的请说一下,这几句的汇编代码如下所示:

0040EE8D push offset @ILT+35(`vcall') (00401028)
0040EE92 push offset string "pa.say:%0x\n" (004260a0)
0040EE97 call printf (004014c0)
0040EE9C add esp,8
0040EE9F push offset @ILT+35(`vcall') (00401028)
0040EEA4 push offset string " s.say:%0x\n" (00426094)
0040EEA9 call printf (004014c0)
0040EEAE add esp,8
0040EEB1 push offset @ILT+35(`vcall') (00401028)
0040EEB6 push offset string "ps.say:%0x\n" (00425084)
0040EEBB call printf (004014c0)
0040EEC0 add esp,8

00401028处的内容为:

00401028 E9 83 00 00 00 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 閮...烫烫烫烫烫烫烫.
0040103C CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 烫烫烫烫烫烫烫烫烫烫
00401050 55 8B EC 83 EC 44 53 56 57 51 8D 7D BC B9 11 00 00 00 B8 CC U嬱冹DSVWQ峿脊....柑
00401064 CC CC CC F3 AB 59 89 4D FC 8B 45 FC C7 00 1C 50 42 00 8B 4D 烫腆玒塎鼖E..PB.婱
00401078 08 51 8B 55 FC 83 C2 04 52 E8 0A 03 00 00 83 C4 08 8B 45 FC .Q婾鼉..R.....兡.婨.
...全文
217 5 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
cattycat 2012-03-23
  • 打赏
  • 举报
回复
vtable的地址吧,如果有多个虚函数,会通过[1]取下一个虚函数地址。
小菩提的尾巴 2012-03-23
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 qscool1987 的回复:]
printf("%0x,\n",*(int*)((int*)ps)[0]);
这个才是虚函数的地址
你那个不符合语法,标准禁止这么做
成员函数指针并不是一个函数指针,他代表两层含义,对于非虚的成员函数代表函数的地址,对于虚函数代表vtable中得索引值,这些在深度探索里面讲得比较清楚
[/Quote]
深度探索那本书刚刚看的,还没看到后面部分,不过谢谢你的回答
又看了一下,发现00401028处是函数的跳转表那里
@ILT+0(??1Person@@QAE@XZ):
00401005 jmp Person::~Person (004010c0)
@ILT+5(?Say@Student@@UAEXXZ):
0040100A jmp Student::Say (00401220)
@ILT+10(??0Student@@QAE@PADHH@Z):
0040100F jmp Student::Student (00401160)
@ILT+15(??1Student@@QAE@XZ):
00401014 jmp Student::~Student (004011d0)
@ILT+20(??0Person@@QAE@PADH@Z):
00401019 jmp Person::Person (00401050)
@ILT+25(_main):
0040101E jmp main (0040edd0)
@ILT+30(?Say@Person@@UAEXXZ):
00401023 jmp Person::Say (00401100)
00401028 jmp `vcall' (004010b0)

而004010b0处则是:
004010B0   mov         eax,dword ptr [ecx]
004010B2 jmp dword ptr [eax]
004010B4 int 3
004010B5 int 3
004010B6 int 3
004010B7 int 3

我觉得mov eax, dword ptr[ecx]应该是取虚表地址,然后jmp到第一个虚函数那里
不过没看到对这个‘vcall’的调用,基本上明白了,在纠结下去也应该没什么意义吧,看看有没有其他高手说一下,明天就速度结贴吧。。。
qscool1987 2012-03-23
  • 打赏
  • 举报
回复
printf("%0x,\n",*(int*)((int*)ps)[0]);
这个才是虚函数的地址
你那个不符合语法,标准禁止这么做
成员函数指针并不是一个函数指针,他代表两层含义,对于非虚的成员函数代表函数的地址,对于虚函数代表vtable中得索引值,这些在深度探索里面讲得比较清楚
iamnobody 2012-03-23
  • 打赏
  • 举报
回复
不符合语法!
pengzhixi 2012-03-23
  • 打赏
  • 举报
回复
printf("pa.say:%0x\n", pa.Say);
本身用printf输出一个函数名就没意义了。

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧