C++中的虚函数表
来源:互联网 发布:铃声剪辑器 mac 编辑:程序博客网 时间:2024/04/27 17:59
本文摘自(www.cnblogs.com/wirelesser/archive/2008/03/09/1097463.html)
大家都知道C++中的虚函数的实现一般是通过虚函数表(C++规范并没有规定具体用哪种方法,但大部分的编译器厂商都选择此方法),下面通过虚函数表来看看C++中虚函数的实现
class A
{
public:
int ai;
virtual void func(){cout<<"A-func"<<endl;}
};
class AA:public A
{
public:
void func(){cout<<"AA-func"<<endl;}
};
int main( )
{
AA *paa = new AA;
A *pa = new A;
}
可以看到paa指向的AA对象中,其子对象A的虚函数表(vftb)地址为0x0047e69c,正好是AA对象的首32位
倘若将类定义改成:
class A
{
public:
int ai;
virtual void func(){cout<<"A-func"<<endl;}
};
class AA:public A
{
public:
//void func(){cout<<"AA-func"<<endl;} 去掉AA中这个虚函数的override.
};
那么可以看到paa中的虚函数表中的第一个项(即从A继承而来的func),和pa中虚函数表的第一个项(A中的func),都指向同一个地方(0x004010f5),可以得出这样一个结论:当派生类没有覆盖(override)基类中的虚函数时,那么这个虚函数就会指向基类的虚函数实现。在C#中也有类似的概念,C#中的override关键字即表明派生类需要改写基类中虚函数项的指向。
在派生类中新增一个virtual func 虚函数
class A
{
public:
int ai;
virtual void func(){cout<<"A-func"<<endl;}
virtual void func2(){cout<<"A-func2"<<endl;}
};
class AA:public A
{
public:
void func(){cout<<"AA-func"<<endl;}
virtual void aa_func(){cout<<"AA-aa_func"<<endl;}
};
对于这份代码,VS2005的debugger并没有正确反映出AA中aa_func的位置(从图中看到vfptr虚函数表只有2项),但是,从图上仍然可以看出paa->aa_func占用了paa->__vfptr表中第三项位置(vfptr+8即表的第三项,每个表项的偏移为4个字节)。另外,我们再次看到如果派生类没有覆盖基类的虚函数,那么,它就和基类指向同一个函数体(两者的func2都指向了A::func2)
让我们回忆一下上一篇关于C++的类型转换的过程:
AA *paa = new AA;
这时候paa指向了AA的一个实例(instance)
A *pa = new AA;
这时候pa指向的仍然是AA的这个实例
因此,pa->func 和 paa->func都指向了AA实例中vftb的第一项,也就是AA:func(),为什么指针可以呈现出多态的原因也就不言而喻了。(对于引用也是同样的道理)
再来看看非虚函数和虚函数的汇编代码:
class A
{
public:
int ai;
virtual void func(){cout<<"A-func"<<endl;} //看看有(没有)virtual的汇编代码
};
class AA:public A
{
public:
};
非虚函数:
paa->A::func();
004010C6 mov ecx,dword ptr [paa]
004010C9 add ecx,4 //将paa对象压栈(偏移4是因为首4个字节保存的是vftb虚函数表)
004010CC call A::func (401046h)
虚函数:
paa->func();
00401230 mov edx,dword ptr [paa] //paa对象->edx
00401233 mov eax,dword ptr [edx] //vftb->eax
00401235 mov ecx,dword ptr [paa] //paa对象->ecx
00401238 mov edx,dword ptr [eax] //vftb的第一项->edx,也就是func所在的位置
0040123A call edx
经过一系列”复杂”的计算,最后edx寄存器里存放的就是func的正确地址,这也叫做late-binding(迟绑定)
最后看看虚函数导致对象的内存布局
当基类中没有虚函数的时候,自然基类也就没有虚函数表,而当基类中有虚函数的时候,编译器产生一个虚函数表,派生类就使用其基类子对象中的虚函数表.
class A
{
public:
int ai;
virtual void func2(){cout<<"A-func2"<<endl;}
};
class AA:public A
{
public:
void func(){cout<<"AA-func"<<endl;}
virtual void aa_func(){cout<<"AA-aa_func"<<endl;}
};
Vftb的第一项是A中的func2(),而第二项是AA中的aa_func
- [C++]C++中的虚函数
- c中的函数指针
- C ++ 中的函数
- C中的随机数函数
- c中的strtok函数
- c语言中的函数
- C中的static函数
- unix中的c函数
- C中的stat()函数
- C中的strncat()函数
- C中的qsort函数
- c中的字符串函数
- C中的access函数
- C语言中的函数
- C中的access函数
- C中的access函数
- C中的access函数
- C中的qsort函数
- 基金选择指标
- 一个简单的Squid服务器
- 标准C++的类型转换符
- 类型转换--c语言
- 零碎的问题记录--持续更新中......
- C++中的虚函数表
- 正则应用之——日期正则表达式
- C++界面库 - Xtreme Toolkit Pro
- Redhat 5.3 Cluster测试二三事
- SWT中的(文件目录对话框)和(文件对话框)
- volatile的用法
- 覆铜经验之我谈
- querystring用法
- ELF动态解析符号过程