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

本文通过具体实例演示了虚函数表的工作原理,展示了派生类如何继承并重写基类的虚函数,同时介绍了如何通过指针操作来访问这些虚函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

////验证  虚函数的组织结构 ,虚函数如何实现一般化操作 ,指针的多种用法(分析 侯俊杰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()

**********************************************************************/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值