我知道C++有一个虚函数列表,对象有指向虚函数列表的指针,对于有虚函数的类对象调用虚函数时通过虚函数列表里面的指针实现的。。但是对于普通的非虚函数是怎么实现调用的呢、? 是怎么找到非虚函数的入口地址? 好像类对象里面只有类的一些数据成员。。求解惑 求详细的内存层次的变化
2013-09-10 20:39
提问者采纳
程序运行时内存中有一个区域【代码区】,所有代码段都存放在这里,包括虚函数和非虚函数 普通函数调用时,直接转换成代码去区的地址,生成文件时就定了 类的虚表可以看成是类的静态数据成员,类的每个对象有个指针指向这个虚表,即为虚表指针 当虚函数调用时,就是从虚表指针找到虚表,进而找到了虚函数的地址
追问
比如:class A{ public:void f(){} }; A a; a.f(); //调用f(); 我知道编译时类中函数会在代码区生成,还有一个偏移量来定位什么的(这不是很懂), 但是a.f是怎么知道代码区f()函数的绝对地址的? 就是想知道运行a.f()时,内存里面发生了什么变化。
回答
1
2
3
4
5
6
|
class
A
{
public
:
void
f() {}
virtual
void
g() {}
};
|
1
2
3
4
5
6
|
class
B :
public
A
{
public
:
void
h() {}
virtual
void
g() {}
};
|
1
2
3
4
5
|
void
Test(A& a)
{
a.f();
a.g();
}
|
以上是代码
下面是Test两个函数调用的汇编代码
1
2
3
4
5
6
7
8
9
10
11
12
|
a.f();
001F6FCE mov ecx,dword ptr [a]
001F6FD1 call A::f (01F1433h)
a.g();
001F6FD6 mov eax,dword ptr [a]
001F6FD9 mov edx,dword ptr [eax]
001F6FDB mov esi,esp
001F6FDD mov ecx,dword ptr [a]
001F6FE0 mov eax,dword ptr [edx]
001F6FE2 call eax
001F6FE4 cmp esi,esp
001F6FE6 call __RTC_CheckEsp (01F12E9h)
|
由此可见,f函数直接寻址(在编译时就已经确定地址了01F1433h),而g函数通过虚指针寻址
追问
恩 很明确,但是觉得类在编译时,类里面的函数只是一个相对地址,但是在连接是才进行重定位为绝对地址,这两个过程存在一个地址修改的问题(根据什么修改的很疑惑) 这样反汇编后肯定是最后的绝对地址。。 希望能够解惑 谢谢你了 先采纳了
-
提问者评价
-
非常感谢