深入理解virtual关键字

深化了解virtual紧张字

简介:深化了解virtual紧张字眼前的机制,了解它存在的来由以及使用它必要注意的成绩。本文将为你揭开virtual的奥秘面纱。

弁言

为什么会写这篇文章?主要是由于项目中的代码多量使用了带virtual紧张字的类,让我以为不吐不快。virtual并没有什么超才能可以化糜烂为神奇,它有其存在的来由,但滥用它是一种十分不成取的错误举动。本文将带你一步一步了解virtual机制,为你揭开virtual的奥秘面纱。

为什么必要virtual

假定我们正在举行一个公用图形化库的计划完成,此中触及2d和3d坐标点的打印,计划出Point2d和Point3d的完成如下:

完善,统统都切合预期。既然云云,我们为什么必要virtual?让我们提个新需求:封装一个坐标点打印接口,输入是坐标点实例,输入是坐标点的值。很快,我们完成了代码:

哦噢,成绩来了,当我们传入3d坐标点实例时,我们的希冀是打印3d坐标点的值,而实践只能打印2d坐标点的值。如今的步骤傻傻分不清坐标点是2d照旧3d,为了让步骤变得更智慧,必要对症下药,而virtual正是该症的药方。只必要更新Point2d接口print的声明即可:

干得标致,统统又规复完善如初。在c++承继干系中完成多态的威力,正是必要virtual的场合。那么它的神奇魔力毕竟从何而来呢?统统要从类数据成员内存布局提及。

类的内存布局

在c++目标模子中,非静态数据成员被设置于每一个类目标之内,静态数据成员则被存放在类目标之外。静态和非静态函数成员也被存放在类目标之外。大大多编译器对类的内存布局办法是按成员的声明排序依次分列,本文的一切例子都是在mac情况下,使用x86_64-apple-darwin21.6.0/clang-1300.0.29.3编译,非virtual版本的Point2d内存布局:

内存布局必要我们注意的是编译器对内存的对齐办法,内存对齐寻常分两步:其一是类成员先按本身轻重对齐,其二是类按最大成员轻重对齐。我们在安插类成员的时分,应该依照成员从大到小的排序声明,如此可以制止不必要的内存添补,节流内存占用。

派生类的内存布局

在c++的承继模子中,一个子类的内存轻重,是其基类的数据成员加上其本人的数据成员轻重的总和。大大多编译器对子类的内存布局是先安插基类的数据成员,然后是本身的数据成员。非virtual版本的Point3d的内存布局:

virtual类的内存布局

当Point2d声明白virtual函数后,对类目标产生了两点严重影响:一是类将产生一系列指向virtual functions的指针,放在表格之中,这个表格被称之为virtual table(vtbl)。二是类实例都被安插一个指针指向干系的virtual table,通常这个指针被称为vptr。为了示例必要,我们重新计划Point2d和Point3d完成:

大大多编译器把vptr安插在类实例的开头处,如今我们来看看virtual版本的Point2d和Point3d的内存布局:

真实内存布局对否如上图所示,很简便,我们一验便知:

紧张中心virtual table的获取在第5行,但是可以当作两步利用:intptr_t vptr2d = *(intptr_t*)&point2d;intptr_t *vtbl2d = (intptr_t*)vptr2d;第一步使vptr2d指向virtual table,第二步将指针转换为数组首地点。然后就可以用vtbl2d逐一调用虚函数。从输入后果看,步骤的确逐一调用到对应的虚函数,virtual类的内存布局和先前我们所画布局图一律。

……

点击链接查察原文,获取更多福利!

https://developer.aliyun.com/article/1052792?utm_content=g_1000361334

版权声明:本文内容由阿里云实名注册用户盲目奉献,版权归原作者一切,阿里云开发者社区不拥有其著作权,亦不承当相应执法责任。具体端正请查察《阿里云开发者社区用户办事协议》和《阿里云开发者社区知识产权保护指引》。假如您发觉本社区中有涉嫌剽窃的内容,填写侵权举报表单举行密告,一经查实,本社区将立刻删除涉嫌侵权内容。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享