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的成本的更多相关文章

  1. java 虚方法。 后面new 那个类, 就调用哪个类的方法 ,而非定义类的方案。 关于父子 类的 呵呵

    java   虚方法.     后面new  那个类, 就调用哪个类的方法 ,而非定义类的方案.  关于父子 类的   呵呵 在多态的情况下,声明为父类类型的引用变量只能调用父类中的方法,但如果此变量 ...

  2. C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决

    1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...

  3. C++ | 继承(基类,父类,超类),(派生类,子类)

    转载:https://blog.csdn.net/Sherlock_Homles/article/details/82927515 文章参考:https://blog.csdn.net/war1111 ...

  4. 访问祖先类的虚方法(直接访问祖先类的VMT,但是这种方法在新版本中未必可靠)

    访问祖先类的虚方法 问题提出 在子类覆盖的虚方法中,可以用inherited调用父类的实现,但有时候我们并不需要父类的实现,而是想跃过父类直接调用祖先类的方法. 举个例子,假设有三个类,实现如下: t ...

  5. servlet、filter、listener继承的基类和获得作用域的方式

    一.servlet: 1.servlet属于j2ee的组件,构建servlet的web project不需要导入项目框架jar包 2.servlet的体系结构:  在j2ee API中,提供给serv ...

  6. 修改tt模板让ADO.NET C# POCO Entity Generator With WCF Support 生成的实体类继承自定义基类

    折腾几天记载一下,由于项目实际需要,从edmx生成的实体类能自动继承自定义的基类,这个基类不是从edmx文件中添加的Entityobject. 利用ADO.NET C# POCO Entity Gen ...

  7. C# 类中的静态字段始终继承自基类

    我们试想一下现在有一个类Parent,它有一个static的int类型字段number,然后如果类Parent有三个子类Child01.Child02和Child03,那么改变Parent.numbe ...

  8. C#抽象类、抽象方法、虚方法

    定义抽象类和抽象方法: abstract 抽象类特点: 1.不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们的实例 2.一个抽象类可以包含抽象和非抽象方法,当一个类 ...

  9. 浅谈C#抽象方法、虚方法、接口

    每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...

  10. C#中virtual(虚方法)的理解以及和abstract(抽象方法)的区别

    Virtual方法(虚方法) virtual 关键字用于在基类中修饰方法.virtual的使用会有两种情况: 情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法.那么在对派生类实例 ...

随机推荐

  1. Excel的最大行数

    使用Excel2007或Excel2010,在“另存为” 菜单中可以选择为“Excel 07-2003 工作薄”,从中我们可以看出,到了2007版以后,存储格式变了,简单一点从扩展名便可以看出,一个是 ...

  2. 【LR】OSGI性能测试实例

    其实我们就两点Ø  确定测试登录最大并发用户数:Ø  事务平均响应时间 (两个查询) 得到这个任务 如何展开测试工作呢? 一.WindowsResources 设置(其实不监控 设不设都行 我感觉)  ...

  3. eclipse手动导入dtd文件

    1.在eclipse的工具栏上按照“Window->Preferences->XML->XML Catalog”依次点下去,然后在右侧选中 User Specified Entrie ...

  4. import Tkinter的时候报错

    在看到图形界面编程的时候,需要导入Tkinter模块,从而在解释器中进行import Tkinter,然后...报错如下: >>> from tkinter import * Tra ...

  5. LeetCode(5) - Longest Palindromic Substring

    这道题要求的是给你一个string, 如“adcdabcdcba",要求返回长度最大的回文子字符串.这里有两个条件,一是子字符串,而是回文.用纯暴力搜索的话,需要用到O(n^3)的时间,必然 ...

  6. 《学习OpenCV》练习题第四章第八题ab

    这道题是利用OpenCV例子程序里自带的人脸检测程序,做点图像的复制操作以及alpha融合. 说明:人脸检测的程序我参照了网上现有的例子程序,没有用我用的OpenCV版本(2.4.5)的facedet ...

  7. LCA of a Binary Tree

    236. Lowest Common Ancestor of a Binary Tree /** * 基础版 * 给定p,q都是在树中 * 有两种情况: * 1. p和q分布在LCA的两侧 * 2. ...

  8. iOS 后台退出app时不执行applicationWillTerminate的临时解决方法

    - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release s ...

  9. Uva 11183 - Teen Girl Squad (最小树形图)

    Problem ITeen Girl Squad Input: Standard Input Output: Standard Output You are part of a group of n  ...

  10. ZOJ-3201 Tree of Tree 树形DP

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3201 题意:给一颗树,每个节点有一个权值,求节点数为n的最大权子 ...