【M24】了解虚方法、多继承、虚基类、RTTI的成本
1、编译器必须实现出C++语言的特性。一般情况下,我们只需要使用这些特性就好了,不需要关心内部的实现细节。但是,有些特性的实现,会对对象的大小和成员方法的执行速度造成影响。因此,有必要了解内部实现的细节。
2、首先考虑虚方法,虚方法是用来实现多态的。多态是指对于指针和引用,表面类型和真实类型不一致的情况下,调用真实类型的虚方法。
3、虚方法有关的实现细节为:
a、父类有一个虚方法表(vtbl),可以认为是一个方法指针的数组(这里注意:对于数组,我们知道元素的类型必须一致,虚方法表中的虚方法类型是不一样的,这里进行了特殊处理),方法指针指向父类的虚方法。
b、子类整体拷贝父类的虚方法表,对于重写的虚方法,在相同位置置换为重写后的虚方法地址,对于新增的虚方法,在数组的尾部添加。
c、对于多态类的对象,内部有一个字段为vptr,指向该类的vtbl。考虑,构造子类对象,首先调用父类构造方法,将vptr初始化为指向父类的虚方法表,然后调用子类的构造方法,将vptr重置为指向子类的虚方法表。
4、需要注意的情况:
a、虚方法表是对应于类的,一个类有一个虚方法表。一般情况下,内存的消耗可以忽略。但是考虑极端的情况,一个父类有1000个虚方法,子类重写一个虚方法,并且有大量类似的子类,出现相同的方法指针,存储多次,就会导致占用大量的内存。
b、对象多一个vptr字段,如果对象本身比较小,vptr占用的内存比例就大了。
c、C++重写为什么要使用virtual关键字?从封装角度而言,类本身是个命名空间,有一个范围的概念。父类是大范围,子类是小范围,在C++中,小范围的名称会隐藏大范围的名称,而不关心名称的类型。使用virtual,其实是告诉编译器不要进行隐藏。把该方法保存到虚方法表中(可以认为是一种特殊情况的隐藏)。
d、在编译的时候,编译器只知道指针或者引用的表面类型。不同类型的指针,本质上没有区别,就是一个地址。重要的是,可以告诉编译器按照什么样的方式去解释指向的内存。这就引出一个问题,把子类对象当成父类对象来解释,不会出现问题。如何保证呢?
第一点,子类对象和父类对象在相同位置都有一个vptr,一般在头部。
第二点,子类虚方法表和父类虚方法表在位置上是一一对应的。
比如:pc->f1(); 产生的代码是:(* pc->vptr[i]) (pc); 找到第i个虚方法指针,解引用,pc传递为this指针。
e、一般情况下,重写要求:子类方法与父类方法,形参表和返回类型完全一致。但是有两种特殊情况:
重写的析构方法,子类父类的方法名各自为本身类名;
父类返回Base*,子类可以返回Derived*,目前C++支持部分的逆变协变,还不支持完全的逆变协变。
f、虚方法不能inlined,这个很好理解。inline可认为编译时文本替换,虚方法运行时确定方法的调用,二者矛盾。
5、多重继承,使问题更复杂。每个对象含有多个vptr,针对不同的父类vtbl,子类产生一个特殊的vtbl。
6、考虑,D->B->A,D->C->A,会导致A的字段在D中有两份,这显然不合理。为了解决这个问题,使用虚拟继承。B,C虚继承A。
7、考虑RTTI,C++提供关键字typeid 获取类的type_info对象。一个类对应于一个type_info对象,类及其所有的对象共享。如 int a, Person p;
typeid(a) 转化为 typeid(int) 求值;
typeid(p) 转化为 typeid(Person) 求值;
8、如果不是多态类,也就是没有虚方法,typeid(*base) 返回表面类型。如果是多态类,typeid(*base) 可以返回真实类型。这意味着内部有一定的实现方法。可以认为,在类的虚方法表中第一项就是当前类的type_info属性。这也解释了,为什么只有多态类才能用typeid求出真实类型。非多态类没有虚方法表。
【M24】了解虚方法、多继承、虚基类、RTTI的成本的更多相关文章
- java 虚方法。 后面new 那个类, 就调用哪个类的方法 ,而非定义类的方案。 关于父子 类的 呵呵
java 虚方法. 后面new 那个类, 就调用哪个类的方法 ,而非定义类的方案. 关于父子 类的 呵呵 在多态的情况下,声明为父类类型的引用变量只能调用父类中的方法,但如果此变量 ...
- C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决
1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...
- C++ | 继承(基类,父类,超类),(派生类,子类)
转载:https://blog.csdn.net/Sherlock_Homles/article/details/82927515 文章参考:https://blog.csdn.net/war1111 ...
- 访问祖先类的虚方法(直接访问祖先类的VMT,但是这种方法在新版本中未必可靠)
访问祖先类的虚方法 问题提出 在子类覆盖的虚方法中,可以用inherited调用父类的实现,但有时候我们并不需要父类的实现,而是想跃过父类直接调用祖先类的方法. 举个例子,假设有三个类,实现如下: t ...
- servlet、filter、listener继承的基类和获得作用域的方式
一.servlet: 1.servlet属于j2ee的组件,构建servlet的web project不需要导入项目框架jar包 2.servlet的体系结构: 在j2ee API中,提供给serv ...
- 修改tt模板让ADO.NET C# POCO Entity Generator With WCF Support 生成的实体类继承自定义基类
折腾几天记载一下,由于项目实际需要,从edmx生成的实体类能自动继承自定义的基类,这个基类不是从edmx文件中添加的Entityobject. 利用ADO.NET C# POCO Entity Gen ...
- C# 类中的静态字段始终继承自基类
我们试想一下现在有一个类Parent,它有一个static的int类型字段number,然后如果类Parent有三个子类Child01.Child02和Child03,那么改变Parent.numbe ...
- C#抽象类、抽象方法、虚方法
定义抽象类和抽象方法: abstract 抽象类特点: 1.不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们的实例 2.一个抽象类可以包含抽象和非抽象方法,当一个类 ...
- 浅谈C#抽象方法、虚方法、接口
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...
- C#中virtual(虚方法)的理解以及和abstract(抽象方法)的区别
Virtual方法(虚方法) virtual 关键字用于在基类中修饰方法.virtual的使用会有两种情况: 情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法.那么在对派生类实例 ...
随机推荐
- DDoS攻防战(一):概述
原文出处: 陶辉的博客 欢迎分享原创到伯乐头条 (此图摘自<Web脚本攻击与防御技术核心剖析>一书,作者:郝永清先生) DDoS,即 Distributed Denial of Ser ...
- 继承View绘制正方形且360旋转
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; impor ...
- Android中设置全屏的方法
在实际的应用程序开发中,我们有时需要把 Activity 设置成全屏显示,一般情况下,可以通过两种方式来设置全屏显示效果.其一,通过在代码中可以设置,其二,通过manifest配置文件来设置全屏. 其 ...
- java多线程之synchronized(线程同步)
一.线程同步,主要应用synchronized关键字: public class TraditionalThreadSynchorinzed { public static void main(Str ...
- javascript常用的小知识
1. oncontextmenu="window.event.returnvalue=false" 将彻底屏蔽鼠标右键 <table border oncontextmenu ...
- 第三百三十八天 how can I 坚持
下午去奥体森林公园跑了个步,好累. 晚上和徐斌同学一起吃了个饭,接触了下杨辉三角,还没整明白,明天看下. 突然想起java 编译,ant脚本. 要精通门技术,还要赶上潮流. 睡觉.
- Spark RDD概念学习系列之为什么会引入RDD?(一)
为什么会引入RDD? 我们知道,无论是工业界还是学术界,都已经广泛使用高级集群编程模型来处理日益增长的数据,如MapReduce和Dryad.这些系统将分布式编程简化为自动提供位置感知性调度. ...
- Netbeans Platform 工程,免安装JDK
使用Netbeans 6.8 创建了一个Netbeans Platform 工程,以Zip形式发布后, 按照以下操作,可 以在客户端免安装JDK: 1. 从已安装JDK的计算机中,提取JDK:eg. ...
- Collection Operators
[Collection Operators] Collection operators are specialized key paths that are passed as the paramet ...
- Options for Debugging Your Program or GCC
[Options for Debugging Your Program or GCC] -g Produce debugging information in the operating system ...