范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

虚函数,虚表深度剖析第一弹

  面向对象,从单一的类开始说起。class A { private:     int m_a;     int m_b; };
  这个类中有两个成员变量,都是int类型,所以这个类在内存中占用多大的内存空间呢?
  sizeof(A), 8个字节,一个int占用四个字节。下图验证:
  这两个数据在内存中是怎样排列的呢?
  原来是这样,我们根据debug出来的地址画出a对象在内存的结构图
  如果 class A 中包含成员函数呢? A 的大小又是多少?class A { public:     void func1() {}     private:     int m_a;     int m_b; };
  直接告诉你答案,类的成员函数多大? 没人能回答你,并且不是本文的重点,类的成员函数是放在代码区的,不算在类的大小内。
  类的对象共享这一段代码,试想,如果每一个对象都有一段代码,光是存储这些代码得占用多少空间?所以同一个类的对象共用一段代码。
  共用同一段代码怎么区分不同的对象呢?
  实际上,你在调用成员函数时,a.func1() 会被编译器翻译为 A::func1(&a),也就是A* const this, this 就是 a 对象的地址。
  所以根据this指针就能找到对应的数据,通过这同一段代码来处理不同的数据。
  接下来我们讨论一下继承,子类继承父类,将会继承父类的数据,以及父类函数的调用权。
  以下的测试可以验证这个情况。class A { public:     void func1() { cout << "A func1" << endl; } private:     int m_a;     int m_b; };  class B : public A { public:     void func2() { cout << "B func2" << endl; } private:     int m_c; };  int main(int argc, char const* argv[]) {     B b;     b.func1();     b.func2();     return 0; }
  输出:// A func1 // B func2
  那么对象b在内存中的结构是什么样的呢?
  继承关系,先把a中的数据继承过来,再有一份自己的数据。
  ​
  每个包含虚函数的类都有一个虚表,虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可。同一个类的所有对象都使用同一个虚表。
  为了指定对象的虚表,对象内部包含指向一个虚表的指针,来指向自己所使用的虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,*__vptr,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。class A { public:     void func1() { cout << "A func1" << endl; }     virtual void vfunc1() { cout << "A vfunc1" << endl; } private:     int m_a;     int m_b; };
  cout << sizeof(A);, 输出12,A中包括两个int型的成员变量,一个虚指针,指针占4个字节。
  a的内存结构如下:
  ​
  虚表是一个函数指针数组,数组里存放的都是函数指针,指向虚函数所在的位置。
  对象调用虚函数时,会根据虚指针找到虚表的位置,再根据虚函数声明的顺序找到虚函数在数组的哪个位置,找到虚函数的地址,从而调用虚函数。
  调用普通函数则不像这样,普通函数在编译阶段就指定好了函数位置,直接调用即可。class A { public:     void func1() { cout << "A func1" << endl; }     virtual void vfunc1() { cout << "A vfunc1" << endl; } private:     int m_a;     int m_b; };  class B : public A { public:     void func1() { cout << "B func1" << endl; }     virtual void vfunc2() { cout << "B vfunc2" << endl; } private:     int m_a; };
  像这样,B类继承自A类,B中又定义了一个虚函数vfunc2, 它的虚表又是怎么样的呢?
  给出结论,虚表如下图所示:
  ​
  我们来验证一下:
  ​A a; B b; void(*avfunc1)() = (void(*)()) *(int*) (*(int*)&a); void (*bvfunc1)() = (void(*)()) *(int*) *((int*)&b); void (*bvfunc2)() = (void(*)()) * (int*)(*((int*)&b) + 4); avfunc1(); bvfunc1(); bvfunc2();
  来解释一下代码: void(*avfunc1)() 声明一个返回值为void, 无参数的函数指针 avfunc1, 变量名代表我们想要取A类的vfunc1这个虚函数。
  右半部分的第一部分,(void(*)()) 代表我们最后要转换成对应上述类型的指针,右边需要给一个地址。
  我们看 (*int(*)&a), 把a的地址强转成int*, 再解引用得到 虚指针的地址。
  *(int*) (*(int*)&a) 再强转解引用得到虚表的地址,最后强转成函数指针。
  同理得到 bvfunc1, bvfunc2, +4是因为一个指针占4个字节,+4得到虚表的第二项。
  覆盖class A { public:     void func1() { cout << "A func1" << endl; }     virtual void vfunc1() { cout << "A vfunc1" << endl; } private:     int m_a;     int m_b; };  class B : public A { public:     void func1() { cout << "B func1" << endl; }     virtual void vfunc1() { cout << "B vfunc1" << endl; } private:     int m_a; };
  子类重写父类的虚函数,需要函数签名保持一致,该种情况在内存中的结构为:
  ​
  多态
  父类指针指向子类对象的情况下,如果指针调用的是虚函数,则编译器会将会从虚指针所指的虚函数表中找到对应的地址执行相应的函数。
  子类很多的话,每个子类都覆盖了对应的虚函数,则通过虚表找到的虚函数执行后不就执行了不同的代码嘛,表现出多态了嘛。
  我们把经过虚表调用虚函数的过程称为动态绑定,其表现出来的现象称为运行时多态。动态绑定区别于传统的函数调用,传统的函数调用我们称之为静态绑定,即函数的调用在编译阶段就可以确定下来了。
  那么,什么时候会执行函数的动态绑定?这需要符合以下三个条件。通过指针来调用函数指针 upcast 向上转型(继承类向基类的转换称为 upcast)调用的是虚函数
  为什么父类指针可以指向子类?
  子类继承自父类,子类也属于A的类型。
  最后通过一个例子来体会一下吧:class Shape { public:     virtual void draw() = 0; };  class Rectangle : public Shape {     void draw() { cout << "rectangle" << endl; } };  class Circle : public Shape {     void draw() { cout << "circle" << endl; } };  class Triangle : public Shape {     void draw() { cout << "triangle" << endl; } };   int main(int argc, char const *argv[]) {     vector v;     v.push_back(new Rectangle());     v.push_back(new Circle());     v.push_back(new Triangle());     for (Shape* p : v) {         p->draw();     }     return 0; }
  有些话是大白话,哈哈,如果这篇文章写得不错,解决了你的疑惑的话,点个赞再走吧!
  不对的地方也请指出来,大家一起学习进步。

LoopCapital预计iPhone产量将进一步下降北京商报讯(记者金朝力王柱力)4月5日,LoopCapital分析师JohnDonovan发表研报表示,苹果可能会将2022年的iPhone生产订单削减至2。45亿至2。5亿之间,色情直播平台Max覆灭记一年获利2。5亿,200多人落网随着网络直播的普及,越来越多非法低俗的色情直播在暗处夹缝生存,不仅踩了道德底线与法律红线,还严重玷污了网络坏境。尽管监管部门审查严厉,可这些涉黄平台依旧猖狂。不少黄播app甚至抢占雷军发起米粉最爱的小米手机投票,仍是这款5年无法被超越的机型2011年8月16号的下午,雷军背对着大屏幕,穿着牛仔裤和黑色的T恤,正式发布了旗下的第一款小米手机。而11年过去了,小米发布了数不胜数的各种机型,但回过头来却不难发现,这些年能够消息称中邮Hinova9SE5G手机4月8日发布,搭载骁龙695IT之家4月5日消息,据爆料博主厂长是关同学消息,中邮Hinova9SE5G将在本月8日发布,外形与华为nova9SE大体相同,处理器采用了骁龙695,支持5G。骁龙6955G这款六款旗舰手机发热与耗电横评再次恭喜你,iPhone13ProMax面向2022年打造的旗舰手机首批已经基本发布完了,如果你还在纠结不知道该如何选择?或者想购入一款性能强悍且发热较低的手机,那么本文也许可以帮助到你。本文将对三星GalaxyS22U小米手机通用!MIUI不懂这几个设置就等于不会用,省电还提升流畅在手机领域,硬件与系统可以说是支撑起这辆马车的两条大腿,硬件决定下限,系统决定体验,除了在硬件上拼刺刀,系统领域的枪林弹雨也是丝毫不弱于硬件上的碰撞。国内诞生了诸如ColorOS,MySQL行锁根据加锁的范围,MySQL里面的锁大致可以分为全局锁表级锁行锁三类。今天学习一下行锁。MySQL的行锁,是由引擎层实现的,InnoDB支持行锁,而MyISAM不支持行锁,这也是My花40万买燃油车的人很悲惨,刘涛是想帮智己上热搜吗?花40万买燃油车的用户是无奈且悲惨的,燃油车提供的性能跟电动车没法比。手握40万的预算,选来选去只能选一个2。0T的四缸机。这是智己汽车联席CEO刘涛在3月30日的智己L7pro媒华为高层出现大变动,任正非的接班人被确认了解更多科技资讯尽在圈聊科技。今天跟大家聊一聊华为高层出现大变动,任正非的接班人被确认!针对华为的相关限制,已经实施了将近三年的时间,这的确给华为造成了不小的损失,但也激起了一个更连环画飞龙传09瓜园定亲潼关借头。。。。。。微信可自定义图标啦!超萌超心爱近来,小编忽然发现小伙伴的微信图标不再是万年不变的图标了,而是萌萌的图标!在小编的追问下,小伙伴就把方法教给小编了,还别说,真的好萌好可爱!首先我们打开iPhone上的快捷指令AP
既爱奇瑞的2。0T,又恋长安的8AT,瑞虎8鲲鹏版和CS75PLUS怎么选?买车最重要的就是看三大件,三大件是指汽车的发动机变速箱底盘,以前都说国产品牌造车技术实力不如合资品牌,只有在新能源技术上狠下功夫,实现弯道超车。然而中国人做事总有一股狠劲,不服输的精酿啤酒厂NewHollandBrewing视觉形象升级NewHollandBrewing成立于1997年,是一家位于美国密歇根州荷兰小镇的精酿啤酒厂,生产啤酒和烈酒。该公司被公认为是工艺酿造和蒸馏革命的领先创新者之一,拥有500多名员高端游艇制造商Jaktar视觉形象设计Jaktar成立于2020年,是一家高端游艇制造商,正如其口号所言专为勘探而设计。游艇由户外运动爱好者IgorMelnikov与荷兰游艇设计工作室Vripack合作设计,灵感来自斯威廉姆斯学院Williams视觉形象升级威廉姆斯学院(Williams)是美国一所文理学院,创立于1793年,位于马萨诸塞州威廉斯敦。该学院代表着美国最引以为傲的教育精髓,规模小质量高,专注本科,崇尚通识和人文教育。在美十大顶级汽车音响品牌介绍现在众多豪华非豪华汽车品牌在音响上都很重视,很多品牌都会采用一些世界知名的音响品牌为自己的汽车加分。那么,这些音响品牌究竟如何呢?笔者找了十个用在汽车上的大名鼎鼎的音响品牌,逐一介聊一款正经上班用的笔记本电脑和普通轻薄本不同,商务本在接口扩展性与外设手感(键盘触控板)方面,普遍做得更用心。此外还有高低温湿度灰尘震动冲击高海拔等耐用性测试,确保电脑稳定运行。今天我们的主角是ThinkPa聊一个彻底逆袭的游戏本系列老PC玩家都知道,微星刚做游戏本那会儿,推出过一台主流价位的游戏本GE60。身为早期的GE系列,这台电脑搭载了GTX660M显卡,i73610QM处理器,售价5999元起,是当时的首发8199元,雷神发布创作大师1610巨幕本2。5K165Hz屏,RTX3060本文转自IT之家作者沐泉昨日雷神正式发布雷神911M创作大师1610巨幕本。产品专为图像后期视频等创作用途设计,搭载英特尔H45处理器,以及RTX3060独显,相比游戏本屏幕素质更雷蛇风行RGBN95空气净化面罩发布,将与沛纳海联名推出环保材料手表本文转自IT之家作者沐泉今日雷蛇正式发布了RazerZephyr风行RGB空气净化面罩,该产品在今年早些时候已经曝光,带有双进气风扇,面罩正面透明,且具有RGB灯光。这款面罩是在新猪王二手3千元能买到游戏本么?今年的游戏本一直比较缺,特别是3050,3050Ti的游戏本,就算有货的,价格也飙到六七千元了。各大平台都10月20日就开始预售了,想等到双十一入手一台笔记本,恐怕有点晚,某些热销ThinkPad发布X13锐龙版超便携商旅本锐龙Pro5650U处理器,5999元本文转自IT之家作者江离今日,联想发布了ThinkPadX13锐龙版超便携商旅本,预售价为5999元。ThinkPadX13锐龙版整机采用轻薄化设计,轻至1。3kg,薄至17。9m