当前位置: 首页 > news >正文

网站改版打造全新网站网站建设预算申请表

网站改版打造全新网站,网站建设预算申请表,外贸网络营销如何选取关键词,蚌埠哪有做网站的点击蓝字关注我们深入理解C 虚函数表C中的虚函数的作用主要是实现了多态的机制。关于多态#xff0c;简而言之就是用父类型别的指针指向其子类的实例#xff0c;然后通过父类的指针调用实际子类的成员函数。Derive d; Base1 *b1 d; Base2 *b2 d; Base3 *b3 虚函数表C中的虚函数的作用主要是实现了多态的机制。关于多态简而言之就是用父类型别的指针指向其子类的实例然后通过父类的指针调用实际子类的成员函数。Derive d; Base1 *b1 d; Base2 *b2 d; Base3 *b3 d; b1-f(); //Derive::f() b2-f(); //Derive::f() b3-f(); //Derive::f()b1-g(); //Base1::g() b2-g(); //Base2::g() b3-g(); //Base3::g()这种技术可以让父类的指针有“多种形态”这是一种泛型技术。所谓泛型技术说白了就是试图使用不变的代码来实现可变的算法。比如模板技术RTTI技术虚函数技术要么是试图做到在编译时决议要么试图做到运行时决议。本文将详细介绍虚函数表的实现及其内存布局。虚函数表概述虚函数表是指在每个包含虚函数的类中都存在着一个函数地址的数组。当我们用父类的指针来操作一个子类的时候这张虚函数表指明了实际所应该调用的函数。C的编译器保证虚函数表的指针存在于对象实例中最前面的位置这样通过对象实例的地址得到这张虚函数表然后就可以遍历其中函数指针并调用相应的函数。按照上面的说法来看一个实际的例子#include iostreamusing namespace std;class Base { public:virtual void f() { cout f() endl; }virtual void g() { cout g() endl; }virtual void h() { cout h() endl; } };int main() {Base t;( ((void(*)())*((int*)(*((int*)t)) 0)) ) ();( ((void(*)())*((int*)(*((int*)t)) 1)) ) ();( ((void(*)())*((int*)(*((int*)t)) 2)) ) ();return 0; }经过VS2017x86测试我们成功地通过实例对象的地址得到了对象所有的类函数。main定义Base类对象t把b转成int *取得虚函数表的地址vtptr就是(int*)(t)然后再解引用并强转成int * 得到第一个虚函数的地址也就是Base::f()即(int*)(*((int*)t))那么第二个虚函数g()的地址就是(int*)(*((int*)t)) 1依次类推。单继承下的虚函数表派生类未覆盖基类虚函数下面我们来看下派生类没有覆盖基类虚函数的情况其中Base类延用上一节的定义。从图中可看出虚函数表中依照声明顺序先放基类的虚函数地址再放派生类的虚函数地址。可以看到下面几点1虚函数按照其声明顺序放于表中。2父类的虚函数在子类的虚函数前面。测试代码#include iostreamusing namespace std;class Base { public:virtual void f() { cout f() endl; }virtual void g() { cout g() endl; }virtual void h() { cout h() endl; } };class Devired :public Base{ public:virtual void x() { cout x() endl; } };int main() {Devired t;(((void(*)()) *((int*)(*((int*)t))))) ();(((void(*)())*((int*)(*((int*)t)) 1))) ();(((void(*)())*((int*)(*((int*)t)) 2))) ();//(((void(*)())*((int*)(*((int*)t)) 3))) ();return 0; }测试效果派生类覆盖基类虚函数再来看一下派生类覆盖了基类的虚函数的情形可见虚表中派生类覆盖的虚函数的地址被放在了基类相应的函数原来的位置 显然的不然虚函数失去意义派生类没有覆盖的虚函数延用基类的测试代码#include iostreamusing namespace std;class Base { public:virtual void f() { cout f() endl; }virtual void g() { cout g() endl; }virtual void h() { cout h() endl; } };class Derive :public Base{ public:virtual void x() { cout x() endl; }virtual void f() { cout Derive::f() endl; } };int main() {Derive t;(((void(*)()) *((int*)(*((int*)t))))) ();(((void(*)())*((int*)(*((int*)t)) 1))) ();(((void(*)())*((int*)(*((int*)t)) 2))) ();//(((void(*)())*((int*)(*((int*)t)) 3))) ();return 0; }测试效果多继承下的虚函数表无虚函数覆盖如果是多重继承的话问题就变得稍微复杂一丢丢主要有几点每个基类都有自己的虚函数表派生类的虚函数地址存依照声明顺序放在第一个基类的虚表最后这点和单继承无虚函数覆盖相同具体见下图所示测试代码#include iostream class Base { public:Base(int mem1 1, int mem2 2) : m_iMem1(mem1), m_iMem2(mem2) { ; }virtual void vfunc1() { std::cout In vfunc1() std::endl; }virtual void vfunc2() { std::cout In vfunc2() std::endl; }virtual void vfunc3() { std::cout In vfunc3() std::endl; }private:int m_iMem1;int m_iMem2; };class Base2 { public:Base2(int mem 3) : m_iBase2Mem(mem) { ; }virtual void vBase2func1() { std::cout In Base2 vfunc1() std::endl; }virtual void vBase2func2() { std::cout In Base2 vfunc2() std::endl; }private:int m_iBase2Mem; };class Base3 { public:Base3(int mem 4) : m_iBase3Mem(mem) { ; }virtual void vBase3func1() { std::cout In Base3 vfunc1() std::endl; }virtual void vBase3func2() { std::cout In Base3 vfunc2() std::endl; }private:int m_iBase3Mem; };class Devired : public Base, public Base2, public Base3 { public:Devired(int mem 7) : m_iMem1(mem) { ; }virtual void vdfunc1() { std::cout In Devired vdfunc1() std::endl; }private:int m_iMem1; };int main() {// Test_3Devired d;int *dAddress (int*)d;typedef void(*FUNC)();/* 1. 获取对象的内存布局信息 */// 虚表地址一int *vtptr1 (int*)*(dAddress 0);int basemem1 (int)*(dAddress 1);int basemem2 (int)*(dAddress 2);int *vtpttr2 (int*)*(dAddress 3);int base2mem (int)*(dAddress 4);int *vtptr3 (int*)*(dAddress 5);int base3mem (int)*(dAddress 6);/* 2. 输出对象的内存布局信息 */int *pBaseFunc1 (int *)*(vtptr1 0);int *pBaseFunc2 (int *)*(vtptr1 1);int *pBaseFunc3 (int *)*(vtptr1 2);int *pBaseFunc4 (int *)*(vtptr1 3);(FUNC(pBaseFunc1))();(FUNC(pBaseFunc2))();(FUNC(pBaseFunc3))();(FUNC(pBaseFunc4))();// .... 后面省略若干输出内容可自行补充return 0; }测试效果派生类覆盖基类虚函数我们再来看一下派生类覆盖了基类的虚函数的情形可见虚表中派生类覆盖的虚函数的地址被放在了基类相应的函数原来的位置派生类没有覆盖的虚函数延用基类的代码如下所示注意这里只给出了类的定义main函数的测试代码与上节一样class Devired : public Base, public Base2, public Base3 { public:Devired(int mem 7) : m_iMem1(mem) { ; }virtual void vdfunc1() { std::cout In Devired vdfunc1() std::endl; }virtual void vfunc1() { std::cout In Devired vfunc1() std::endl; }virtual void vBase2func1() { std::cout In Devired vfunc1() std::endl; }private:int m_iMem1; };测试效果钻石型虚继承该继承还是遵循上述的所有原则我们直接来测试。测试代码// 测试四钻石型虚继承//虚基指针所指向的虚基表的内容 // 1. 虚基指针的第一条内容表示的是该虚基指针距离所在的子对象的首地址的偏移 // 2. 虚基指针的第二条内容表示的是该虚基指针距离虚基类子对象的首地址的偏移#pragma vtordisp(off) #include iostream using std::cout; using std::endl;class B { public:B() : _ib(10), _cb(B) {}virtual void f(){cout B::f() endl;}virtual void Bf(){cout B::Bf() endl;}private:int _ib;char _cb; };class B1 : virtual public B { public:B1() : _ib1(100), _cb1(1) {}virtual void f(){cout B1::f() endl;}#if 1virtual void f1(){cout B1::f1() endl;}virtual void Bf1(){cout B1::Bf1() endl;} #endifprivate:int _ib1;char _cb1; };class B2 : virtual public B { public:B2() : _ib2(1000), _cb2(2) {}virtual void f(){cout B2::f() endl;} #if 1virtual void f2(){cout B2::f2() endl;}virtual void Bf2(){cout B2::Bf2() endl;} #endif private:int _ib2;char _cb2; };class D : public B1, public B2 { public:D() : _id(10000), _cd(3) {}virtual void f(){cout D::f() endl;}#if 1virtual void f1(){cout D::f1() endl;}virtual void f2(){cout D::f2() endl;}virtual void Df(){cout D::Df() endl;} #endif private:int _id;char _cd; };int main(void) {D d;cout sizeof(d) endl;return 0; }测试效果1class D size(52): 1 --- 1 0 | --- (base class B1) 1 0 | | {vfptr} 1 4 | | {vbptr} 1 8 | | _ib1 112 | | _cb1 1 | | alignment member (size3) 1 | --- 116 | --- (base class B2) 116 | | {vfptr} 120 | | {vbptr} 124 | | _ib2 128 | | _cb2 1 | | alignment member (size3) 1 | --- 132 | _id 136 | _cd 1 | alignment member (size3) 1 --- 1 --- (virtual base B) 140 | {vfptr} 144 | _ib 148 | _cb 1 | alignment member (size3) 1 --- 1 1D::$vftableB1: 1 | D_meta 1 | 0 1 0 | D::f1 1 1 | B1::Bf1 1 2 | D::Df 1 1D::$vftableB2: 1 | -16 1 0 | D::f2 1 1 | B2::Bf2 1 1D::$vbtableB1: 1 0 | -4 1 1 | 36 (Dd(B14)B) 1 1D::$vbtableB2: 1 0 | -4 1 1 | 20 (Dd(B24)B) 1 1D::$vftableB: 1 | -40 1 0 | D::f 1 1 | B::Bf 1总结几个原则单继承虚表中派生类覆盖的虚函数的地址被放在了基类相应的函数原来的位置派生类没有覆盖的虚函数就延用基类的。同时虚函数按照其声明顺序放于表中父类的虚函数在子类的虚函数前面。多继承每个基类都有自己的虚函数表派生类的虚函数地址存依照声明顺序放在第一个基类的虚表最后安全性问题当我们直接通过父类指针调用子类中的未覆盖父类的成员函数编译器会报错但通过实验我们可以用对象的地址访问到各个子类的成员函数就违背了C语义操作会有一定的隐患当我们使用时要注意这些危险的东西*声明本文于网络整理版权归原作者所有如来源信息有误或侵犯权益请联系我们删除或授权事宜。戳“阅读原文”我们一起进步
http://wiki.neutronadmin.com/news/31785/

相关文章:

  • 柳州住房和城乡建设局网站群晖wordpress域名
  • 四川建设厅官方网站证书查询企业微信网站开发公司
  • 江干区住房和城乡建设局网站郑州网站建设工作
  • 个人做广播网站需要注意什么镇江建设网站公司
  • 网站排名优化工薪待遇网站建设公司咨询
  • 网站+做+app建大型网站
  • 用ps做网站的网页框架网站建设招标需求
  • 天津品牌网站建设好处欧美网站欣赏
  • 怎么找回网站如何编写网站
  • 安徽网站建设调查报告排名优化公司好不好
  • 广州市建设注册中心网站首页网站建设域名和空间续费
  • 东莞市手机网站建设网站登记备案
  • 作风建设年 网站青岛开发区网站
  • 北京公司建网站一般需要多少钱网站开发与网站设计区别
  • 网站谷歌排名医院网站建设策划书
  • 济南哪里做网站wordpress侧边栏目录菜单
  • 长沙做网站湖南微联讯点不错wordpress文件无法创建目录下
  • 医疗网站设计风格宁波优化关键词首页排名
  • 公司建立网站费用织梦网站修改教程视频教程
  • 电商网站开发人员北京做网站公司
  • 网站备案完成深圳福田网站建设专业公司
  • 公司网站要更新深圳网页设计公司有哪些
  • php网站后台忘记密码设计网站的关键点
  • 搭建企业资料网站做电子商务网站建设工资多少钱
  • 高校后勤网站建设要求网站建设推销员话术
  • 衡水哪有做网站的wordpress手机端插件下载
  • 宁波优化网站排名公司推荐qq交流群功能介绍
  • 网站运营和seo的区别网站费做进什么科目
  • 化妆品产品的自建网站哟哪些为什么建设部网站进不去
  • 做网站什么公司加强网站安全建设说明报告范文