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()
**********************************************************************/
#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()
**********************************************************************/
相关文章推荐
- MySQL源码分析及核心内幕之3 -- 源码调试之Eclipse C/C++
- MySQL源码分析及核心内幕之3 -- 源码调试之Eclipse C/C++
- struts2源码分析--IOC容器的实现(操作以及容器的初始化)
- C也可以通过精心封装某些函数功能实现重用,那C++的类有什么优点吗(从面向对象的三大属性进行分析)
- RTTI、虚函数和虚基类的实现方式、开销分析及使用指导(虚函数的开销很小,就2次操作而已)
- Scala深入浅出进阶经典 第41讲:List继承体系实现内幕和方法操作源码揭秘
- 第二人生的源码分析(4)Log调试功能的实现
- 动态联编实现原理分析 C++虚函数地址
- MySQL源码分析及核心内幕之2 -- 源码调试之gdb
- 第二人生的源码分析(4)Log调试功能的实现
- Collections集合静态工具可以让非同步进行同步操作的源码分析
- Babel插件源码分析与babel.transform和babylon.parse操作AST实现效果
- scala-41:List继承体系实现内幕和方法操作源码揭秘
- 41.List继承体系实现内幕和方法操作源码揭秘
- C++ 用注册表可以对计算机实现的操作
- C++虚函数多态性的实现与分析+虚继承的实现与分析
- Qt实现GUI的二进制文件读写操作(源码分析+工程打包+测试例子)
- 第二人生的源码分析(4)Log调试功能的实现
- 【GamingAnywhere源码分析之知识补充四】C操作Windows AD实现用户身份认证
- 一个封装好的C++比特数组BitArray,可以对位进行直接操作