C++中虚基类在派生类中的内存布局
在派生类对象里,按照继承声明顺序依次分布基类对象,最后是派生类数据成员。
若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
派生类独有的虚函数被加在第一个基类的虚函数表后面。
虚拟继承:
在派生类对象里,按照继承声明顺序依次分布非虚基类对象,然后是派生类数据成员,最后是虚基类对象。
若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
若直接从虚基类派生的类没有非虚父类,且声明了新的虚函数,则该派生类有自己的虚函数表,在该派生类头部;否则派生类独有的虚函数被加在第一个非虚基类的虚函数表后面。
直接从虚基类派生的类内部还有一个虚基类表指针(一个隐藏的“虚基类表指针”成员,指向一个虚基类表),在数据成员之前,非虚基类对象之后(若有的话)。
虚基类表中第一个值是该虚基类表到派生类起始地址的偏移;之后的值依次是该派生类的虚基类到该表位置的地址偏移(虚基类对象的地址与派生类的“虚基类表指针”之间的偏移量)。对于虚函数表指针和虚基类表指针:
当单继承且非虚继承时:每个含有虚函数的表只有一个虚函数表,所以只需要一个虚表指针即可;
当多继承且非虚继承时:一个子类有几个父类则会有几个虚函数表,所以就有和父类个数相同的虚表指针来标识;
总之,当时非虚继承时,不需要额外增加虚函数表指针。
当虚继承时:无论是单虚继承还是多虚继承,需要有一个虚基类表来记录虚继承关系,所以此时子类需要多一个虚基类表指针;而且只需要一个即可。
当虚继承时可能出现一个类中持有多个虚函数表的情况:无论是单虚继承还是多虚继承,
如果子类没有构造函数和析构函数,且子类中的虚函数都是在父类中出现的虚函数,这个时候不需要增加任何虚表指针;只需要像多继承那个持有父类个数的虚表指针来标识即可;
如果子类中含有构造函数或者析构函数或二者都有,则在子类中只要每出现一个父类中的虚函数则需要增加一个虚函数表指针来标识此类的虚函数表;
无论是否含有构造函数或者虚构函数,只要继承都是虚继承且出现了父类中没有出现的虚函数,则在子类中需要再增加一个徐函数表指针;如果其中有一个是非虚继承,则按照最省空间的原则,不需要增加虚函数表指针,因为这个时候可以和非虚基类共享一个虚函数表指针。
C++中虚基类在派生类中的内存布局的更多相关文章
- 详解C++中基类与派生类的转换以及虚基类
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
- (转) C++中基类和派生类之间的同名函数的重载问题
下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...
- C++基类、派生类、虚函数的几个知识点
1.尽管派生类中含有基类继承来的成员,但派生类初始化这部分变量需要调用基类的构造函数. class A { private: int x; virtual void f(){cout<<& ...
- c++中基类与派生类中隐含的this指针的分析
先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...
- c++ 的类 和 类继承, 什么是c++中的基类和派生类?
闲云潭影日悠悠,物换星移几度秋 你既然已经做出了选择, 又何必去问为什么选择.鬼谷绝学的要义, 从来都不是回答, 而是抉与择 普通类 #ifndef TABTENN0_H_ #define TABTE ...
- 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
- C++基类和派生类之间的转换
本文讲解内容的前提是派生类继承基类的方式是公有继承,关键字public 以下程序为讲解用例. #include<iostream> using namespace std; class A ...
- OOP1(定义基类和派生类)
面向对象程序设计基于三个基本概念:数据抽象,继承和动态绑定 数据抽象是一种依赖于接口和实现分离的编程技术.继承和动态绑定对程序的编号有两方面的影响:一是我们可以更容易地定义与其它类相似但不完全相同的类 ...
- C++学习21 基类和派生类的赋值
在C/C++中,经常会发生数据类型转换,例如整型数据可以赋值给浮点型变量,在赋值之前,先把整型数据转换为浮点型:反过来,浮点型数据也可以赋值给整型变量. 数据类型转换的前提是,编译器知道如何对数据进行 ...
- 基类和派生类--this
基类指针在程序运行的时候的确指向的是一个派生类的对象,但指针的类型仍然是基类指针.C++是一种强类型语言,因此不能用基类指针类型的指针直接调用派生类:而且,同一个类可能有多种不同的派生类,因此不知道实 ...
随机推荐
- HDU 1495 很可乐 (DFS)
题目链接:很可乐 解析:一个瓶子,容量为s.两个杯子,容量分别为n和m,问最少多少次倾倒才干将一瓶可乐均分为两份. 直接模拟每次的倾倒.然后递归求解. 能够加个预判的条件,要是s是奇数的时候,不管怎样 ...
- (字符串)最长公共字串(Longest-Common-SubString,LCS)
题目: 给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa].二者的最长公共子串为[aba],长度为3. 子序列是不要求连续的,字串必须是连续的. 思路与代码: 1.简 ...
- 把Linux目录挂载到开发板、设置开发板从NFS启动、取消开发板从NFS启动
声明:文中"PC虚拟机Linux"是指在PC上安装了虚拟机,然后在虚拟机中装的Linux. 关于NFS的详细介绍可参考:http://www.cnblogs.com/nufangr ...
- 获取html元素的XPath路径
<!DOCTYPE html> <html> <head> <script src="/jquery/jquery-1.11.1.min.js&qu ...
- 解决Unable to load component class org.sonar.scanner.report.ActiveRulesPublisher/Unable to load component interface org.sonar.api.batch.rule.ActiveRules: NullPointerException
解决办法 Delete the directory data/es in your SonarQube installation. Restart SonarQube.
- SQLite的升级(转)
做Android应用,不可避免的会与SQLite打交道.随着应用的不断升级,原有的数据库结构可能已经不再适应新的功能,这时候,就需要对SQLite数据库的结构进行升级了. SQLite提供了ALTER ...
- 突破单机多实例Elasticsearch
默认大家都是单机单实例es,在实验环境下想尽可能模拟各种场景.单机多实例就出来了... 实验拓扑图 01.es安装这里就不说了 详情:http://www.cnblogs.com/xiaochina/ ...
- OpenWrt中wifidog的配置及各节点页面参数
修改/etc/wifidog.conf, 只需要修改文件的前半部分, 其他都保持默认 GatewayID default GatewayInterface br-lan GatewayAddress ...
- 【laravel54】如果开启了自带的时间戳(Y-h-m H:s:m),getInsertId一定要手动加上created_at 和 updated_at字段填充
[laravel54]如果开启了自带的时间戳(Y-h-m H:s:m),getInsertId一定要手动加上created_at 和 updated_at字段填充
- linux账户密码安全策略
前言 对于服务器安全来说,服务器的账号密码是很重要的事情 我们可以选择取消账号密码登陆,只使用公钥登录,但有时可能并不方便 这里告诉大家账号密码如何管理更加安全 一.账号密码最大使用天数 在/etc/ ...