您的位置:首页 > 编程语言 > C语言/C++

C++虚函数实现一般化操作内幕分析(源码VC6.0可以直接调试)

2008-06-21 20:42 721 查看
////验证 虚函数的组织结构 ,虚函数如何实现一般化操作 ,指针的多种用法(分析 侯俊杰MFC深入浅出+最近指针学习 = 写出验证代码) ;
#include<iostream.h>
#include<stdio.h>
typedef unsigned int uint ;
class ClassA { public:
int m_data1; int m_data2;
void func1() { cout<<"classA func1"<<endl ;}
void func2() { cout<<"classA func2"<<endl ;}
virtual void vfunc1() { cout<<"classA vfunc1"<<endl ;}
virtual void vfunc2() { cout<<"classA vfunc2"<<endl ;} };
class ClassB :public ClassA { public:
int m_data3;
virtual void vfunc1() { cout<<"classB vfunc1"<<endl ;}
virtual void vfunc3() { cout<<"classB vfunc3"<<endl ;} } ;

void main(void) {
cout<<sizeof(ClassA)<<endl; ///12= (1vtableaddr + 2ClassAdata)*4
cout<<sizeof(ClassB)<<endl; ///16= (1vtableaddr + 2ClassAdata +1ClassBdata)*4
ClassA a; ClassB b ,c;
a.m_data1 = 1 ; a.m_data2 = 2 ;
b.m_data1 = 3 ; b.m_data2 = 4; b.m_data3 = 5;
uint *pClassData;
void (*pfun)(void);
uint *pfunadd ;
uint (*pfunadd2)[3];
pClassData = (uint*)&a; ////获得a对象的数据空间
////数据结构为 vfuntableAddr ,m_data1 ,m_data2
cout<<"A "<<*pClassData<<" "<<*(pClassData+1)<<" "<<*(pClassData+2)<<" "<<endl;
pfunadd = (uint *)(*pClassData) ; ////获得vfuntableAddr
////vfunc1 (A) ,vfunc2 (A),不确定
cout<<"A vfun "<<*(pfunadd)<<" "<<*(pfunadd+1)<<" "<<*(pfunadd+2)<<" "<<endl;
/////----------------------- pClassData = (uint*)&b;////获得b对象的数据空间
////数据结构为 vfuntableAddr ,m_data1 ,m_data2 ,m_data3
cout<<"B "<<*pClassData<<" "<<*(pClassData+1)<<" "<<*(pClassData+2)<<" "<<*(pClassData+3)<<" "<<endl;
pfunadd2 = (uint (*)[3])(*pClassData); /////地址值直接转换为指向数组的指针
////vfunc1 (B) ,vfunc2 (A),不确定
cout<<"B vfun "<<(*pfunadd2)[0]<<" "<<(*pfunadd2)[1]<<" "<<(*pfunadd2)[2]<<" "<<endl;
/////----------------------- pClassData = (uint*)&c; cout<<"C "<<*pClassData<<" "<<endl;
pfunadd = (uint *)(*pClassData) ; ///目的:比较b,c虚函数表是否一样,输出结果表明一样
cout<<"C vfun "<<*pfunadd<<" "<<*(pfunadd+1)<<" "<<*(pfunadd+2)<<" "<<endl;
/////----------------------
pfun = (void(*)())(*pfunadd); ///测试classdata第一个字存储虚函数表入口地址 则取表中值就是第一个虚函数执行地址
(*pfun)(); ///测试结果表明该处运行的是ClassB 的 vfunc1();
pfun = (void(*)())(*(pfunadd+1)); //ClassA 的 vfunc2();
(*pfun)();
pfun = (void(*)())(*(pfunadd+2)); //ClassB 的 vfunc3();
(*pfun)();
cout<<"----------------"<<endl;
ClassA *p = &b; ////数据空间没有改变,即虚函数表没有改变&&&&& 这是实现一般化操作的关键所在
p->vfunc1();
((ClassA)b).vfunc1(); ////强制转换实际上先完成一个拷贝,再来按转换类型裁剪/延伸数据空间。
cout<<((ClassA)b).m_data1<<endl; ////对象强制转换时,会覆盖原数据空间的虚函数表入口地址(测试结果得出,个人观点),其他不变
}
/*******总结**********************************************************
派生类继承基类时,首先拷贝一份基类的虚函数表,再来重载,增加自己的虚函数
ClassA
vptr ----(*vfunc1)()--- ClassA::vfunc1()
(*vfunc2)()--- ClassA::vfunc2()
ClassB
vptr ----(*vfunc1)()--- ClassB::vfunc1() 虚函数表中定义的函数首地址改变
(*vfunc2)()--- ClassA::vfunc2()
**********************************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐