什么是对象模型

有两个概念可以解释C++对象模型:

语言中直接支持面向对象程序设计的部分。
对于各种支持的底层实现机制。

类中成员分类

数据成员分为静态和非静态,成员函数有静态非静态以及虚函数

class data members:static和nonstatic

class data functions:static、nonstatic和virtual

比如:

class Base
{
public:Base(int i) :baseI(i){};int getI(){ return baseI; }static void countI(){};virtual void print(void){ cout << "Base::print()"; }virtual ~Base(){}private:int baseI;static int baseS;
};

对象模型分类

简单对象模型:这个模型非常地简单粗暴。在该模型下,对象由一系列的指针组成,每一个指针都指向一个数据成员或成员函数,也即是说,每个数据成员和成员函数在类中所占的大小是相同的,都为一个指针的大小。这样有个好处——很容易算出对象的大小,不过赔上的是空间和执行期效率。所以这种对象模型并没有被用于实际产品上。

表格驱动对象模型:把类中的数据分成了两个部分:数据部分与函数部分,并使用两张表格,一张存放数据本身,一张存放函数的地址(也即函数比成员多一次寻址),而类对象仅仅含有两个指针,分别指向上面这两个表。这样看来,对象的大小是固定为两个指针大小。这个模型也没有用于实际应用于真正的C++编译器上。

C++对象模型:正在使用的

在此模型下,nonstatic 数据成员被置于每一个类对象中,而static数据成员被置于类对象之外。static与nonstatic函数也都放在类对象之外,而对于virtual 函数,则通过虚函数表+虚指针来支持:

  1. 每个类生成一个表格,称为虚表(virtual table,简称vtbl)。虚表中存放着一堆指针,这些指针指向该类每一个虚函数。虚表中的函数地址将按声明时的顺序排列
  2. 每个类对象都拥有一个虚表指针(vptr),由编译器为其生成。虚表指针的设定与重置皆由类的复制控制(也即是构造函数、析构函数、赋值操作符)来完成。vptr的位置为编译器决定,传统上它被放在所有显示声明的成员之后,不过现在许多编译器把vptr放在一个类对象的最前端(也就是说对象的地址就是vptr的地址)
  3. 虚函数表的前面设置了一个指向type_info的指针,用以支持RTTI(Run Time Type Identification,运行时类型识别)。RTTI是为多态而生成的信息,包括对象继承关系,对象本身的描述等,只有具有虚函数的对象在会生成。

单继承(父类含虚函数)

原则:

对普通单继承而言

  1. 子类与父类拥有各自的一个虚函数表
  2. 若子类并无overwrite父类虚函数,用父类虚函数
  3. 若子类重写(overwrite)了父类的虚函数,则子类虚函数将覆盖虚表中对应的父类虚函数
  4. 若子声明了自己新的虚函数,则该虚函数地址将扩充到虚函数表最后
 1 #include <iostream>
 2 using namespace std;
 3
 4 class Base
 5 {
 6 public:
 7     virtual void fun1(){ cout << "Base fun1" << endl; }
 8     virtual void fun2(){ cout << "Base fun2" << endl; }
 9 private:
10     int a;
11 };
12
13 class Derive :  public Base
14 {
15 public:
16     void fun2(){ cout << "Derive fun2" << endl; }
17     virtual void fun3(){}
18 private:
19     int b;
20 };
21
22 int main()
23 {
24     Base b;
25     Derive d;
26     Base *p = &d;
27     p->fun1();
28     p->fun2();
29
30     system("pause");
31     return 0;
32 }

输出:

调试:

对象模型:

事实上vs调试并不能看到完整信息(比如virtual fun3以及之后提到到虚基类指针),正确的应该是

一般多继承

这里讲的是不考虑菱形继承的多继承,因为菱形继承需要用到虚继承,放到之后考虑

原则:

  1. 若子类新增虚函数,放在声明的第一个父类的虚函数表中
  2. 若子类重写了父类的虚函数,所有父类的虚函数表都要改变:如fun1
  3. 内存布局中,父类按照其声明顺序排列
 1 #include <iostream>
 2 using namespace std;
 3
 4 class Base1
 5 {
 6 public:
 7     virtual void fun1(){}
 8 private:
 9     int m_base1;
10 };
11
12 class Base2
13 {
14 public:
15     virtual void fun1(){}
16     virtual void fun2(){}
17 private:
18     int m_base2;
19 };
20
21 class Derive :  public Base1,public Base2
22 {
23 public:
24     void fun1(){}
25     virtual void fun3(){}
26 private:
27     int m_derive;
28 };
29
30 int main()
31 {
32     Base1 b1;
33     Base2 b2;
34     Derive d;
35
36     cout <<"b1:" <<sizeof(b1) << endl;
37     cout << "b2:" << sizeof(b2) << endl;
38     cout <<"d:" << sizeof(d) << endl;
39     system("pause");
40     return 0;
41 }

输出:

各个类对象的大小

调试:注意观察fun1

对象模型:

简单虚继承

原则:

虚继承解决了菱形继承中最派生类拥有多个间接父类实例的情况

  1. 虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个新的虚函数指针(vptr)以及一张虚函数表。该vptr位于对象内存最前面(对比非虚继承:直接扩展父类虚函数表)
  2. 虚继承的子类也单独保留了父类的vprt与虚函数表
  3. 虚继承的子类有虚基类表指针(vbptr)

在C++对象模型中,虚继承而来的子类会生成一个隐藏的虚基类指针(vbptr),在Microsoft Visual C++中,虚基类表指针总是在虚函数表指针之后,因而,对某个类实例来说,如果它有虚基类指针,那么虚基类指针可能在实例的0字节偏移处(该类没有vptr时,vbptr就处于类实例内存布局的最前面,否则vptr处于类实例内存布局的最前面),也可能在类实例的4字节偏移处。

虚基类表也由多个条目组成,条目中存放的是偏移值。

第一个条目存放虚基类表指针(vbptr)所在地址到该类内存首地址的偏移值

第二、第三...个条目依次为该类的最左虚继承父类、次左虚继承父类...的内存地址相对于虚基类表指针的偏移值。

 1 #include <iostream>
 2 using namespace std;
 3
 4 class Base
 5 {
 6 public:
 7     virtual void fun1(){}
 8     virtual void fun2(){}
 9 private:
10     int m_base;
11 };
12
13 class Derive : virtual public Base
14 {
15 public:
16     void fun1(){}
17     virtual void fun3(){}
18 private:
19     int m_derive;
20 };
21
22 int main()
23 {
24     Base b;
25     Derive d;
26
27     system("pause");
28     return 0;
29 }

对象模型:

 

菱形虚继承

菱形虚继承是多继承和虚继承的复合,直接画一个对象模型吧:

笔记原图:

参考:图说C++对象模型:对象内存布局详解

转载于:https://www.cnblogs.com/raichen/p/5744300.html

C++对象模型:单继承,多继承,虚继承相关推荐

  1. c/c++入门教程 - 2.4.6 继承、公共继承、保护继承、私有继承、virtual虚继承(概念、语法、方式、构造和析构顺序、同名成员处理、继承同名静态成员处理、多继承语法、菱形继承、钻石继承)

    目录 4.6 继承 4.6.1 继承的基本语法 4.6.2 继承方式 4.6.3 继承中的对象模型 4.6.4 继承中构造和析构顺序 4.6.5 继承同名成员处理方式 4.6.6 继承同名静态成员处理 ...

  2. 继承详解(虚继承实现原理)

    继承的概念及定义 概念: ​ 继承机制是面向对象程序设计为了提高代码复用率的一种手段,它可以保持原类特性的基础上进行拓展,简单来说继承是类层次的复用. 接下来我们来看一个简单的继承 class Per ...

  3. 菱形继承和虚继承、对象模型和虚基表

    1.菱形继承(钻石继承):两个子类继承同一父类,而又有子类同时继承这两个子类.例如B,C两个类同时继承A,但是又有一个D类同时继承B,C类. 2.菱形继承的对象模型 class A { public: ...

  4. 内存首地址为1000h_C++虚继承,菱形继承,内存分布

    前言 在叙述C++虚继承之前,我先给大家抛出一个问题.例如现在有4个类,分别是class A, class B, class C, class D.它们的关系如下图. 如上如所示,class B和cl ...

  5. C++继承详解三 ----菱形继承、虚继承

    转载:http://blog.csdn.net/pg_dog/article/details/70175488 今天呢,我们来讲讲菱形继承与虚继承.这两者的讲解是分不开的,要想深入了解菱形继承,你是绕 ...

  6. 一文读懂C++虚继承的内存模型

    一文读懂C++虚继承的内存模型 1.前言 2.多继承存在的问题 3.虚继承简介 4.虚继承在标准库中的使用 5.虚继承下派生类的内存布局解析 6.总结 1.前言 C++虚继承的内存模型是一个经典的问题 ...

  7. 继承(下)----虚继承

    单继承&多继承 一个子类只有一个直接父类时称这种继承关系为单继承. 一个子类有两个或者两个以上的父类时称这种继承关系为多继承. 菱形继承 ---------特殊的多继承 有很大的缺点: 二义性 ...

  8. 虚函数、纯虚函数、虚继承、多继承

    来源:http://www.tnove.com/?p=57 C++的一个特征是多太,其中多态主要表现在 1.编译时多态  函数overload实现 2.运行是多态  虚函数override实现 其中虚 ...

  9. C++语法——详解虚继承

    目录 一.什么是虚继承 二.虚继承原理 三.虚继承使用注意事项 一.什么是虚继承 所谓虚继承(virtual)就是子类中只有一份间接父类的数据.该技术用于解决多继承中的父类为非虚基类时出现的数据冗余问 ...

最新文章

  1. 滴滴算法大赛算法解决过程(实时更新)
  2. 静态资源java 配置文件_java web 静态资源访问配置三种方式
  3. 消息队列之JMS和AMQP对比
  4. Visual Studio内存泄漏检测
  5. 程序员修神之路--容器技术为什么会这么流行(记得去抽奖)
  6. 全国计算机一级选择题汇总,全国计算机一级考试选择题训练及答案
  7. c++ using 前置声明_每日优鲜前置仓模式的配货优化方案案例介绍
  8. 协议详解_I2C协议详解
  9. SQL Server 轻松解决令你头疼的sa登录
  10. 一个计算机高手的成长zz
  11. 玻璃质感_几何体素描画法:几何体画法步骤教程和玻璃质感画法教程,快学习...
  12. [C#]通过ARP获取Mac与IP的对应表
  13. 五、文章详情页制作及跳转功能实现《iVX低代码/无代码个人博客制作》
  14. 常用的锂电池充电IC芯片
  15. 《未来行业前景必看》大数据未来的发展趋势!
  16. 深度学习 - 生成对抗网络
  17. 13个坏习惯让IT工作者过度劳累
  18. 【数理统计】假设检验
  19. 成人大专计算机统考的操作详解,成人大专计算机统考选择题汇总
  20. group by left join where 使用总结

热门文章

  1. 【网络安全面试题】——如何渗透测试文件目录穿越
  2. PowerShell监控——监控共享打印机 获取打印记录、打印人员、打印文件等详细信息
  3. SuseLinux详解(2)——网络设置静态IP 网关 DNS的方法
  4. 设计模式04_抽象工厂
  5. 添加列oracle默认值,Oracle 11g增加列,并带默认值的新特性
  6. 月薪2W和月薪10W的差别,怎么判断一个产品经理的专业水平高低?
  7. ssm练手小项目_20 个 JavaScript+Html+CSS 练手的小项目
  8. ubuntu boot空间不足_windows10安装ubuntu双系统教程(绝对史上最详细)
  9. 平面直角坐标系中的旋转公式_初一下学期,平面直角坐标系中求图形面积,转化与化归思想的体现...
  10. Android Studio 设置主题及字体