C++目前使用的对象模型:

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

1)每个类生成一个表格,称为虚表(virtual table,简称vtbl),虚函数表中存在一堆指针,这些指针指向该类的每一个虚函数,虚表中的函数地址按照声明时的顺序排列

2)每个类对象都有一个虚表指针(简称vptr),由编译器为其生成,虚表指针的设定和重置皆由类的相关函数控制(构造函数,析构函数,赋值操作符),虚表指针vptr的位置由编译器决定,一般编译器把vptr放在一个类对象的最前端(也就是说对象的地址就是vptr的地址)

3)虚函数表的前面设置了一个指向type-info的指针,用以支持RTTI(Run Time Type Identification,运行时类型识别),RTTI是为支持多态生成的信息,包括对象的继承关系,对象本身的描述等,只有具有虚函数的对象才会生成

样例:

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;
};

单继承(父类含虚函数)

原则:

  1.子类和父类各自拥有一个虚函数表

  2.若子类并没有overwrite父类虚函数,那么子类就使用父类虚函数

  3.若子类overwrite了父类虚函数,则子类虚函数将覆盖虚子类虚函数表中对应的父类虚函数

  4.若子类声明了自己的虚函数,则该虚函数地址将扩充到虚函数表最后

样例:

#include <iostream>
using namespace std; class Base
{
public:
virtual void fun1()
{
cout << "Base fun1" << endl;
}
virtual void fun2()
{
cout << "Base fun2" << endl;
}
private:
int a;
}; class Derive : public Base
{
public:
void fun2()
{
cout << "Derive fun2" << endl;
}
virtual void fun3() {}
private:
int b;
}; int main()
{
Base b;
Derive d;
Base *p = &d;
p->fun1();
p->fun2(); return ;
}
/*
程序运行结果: Base fun1
Derive fun2 */

一般多继承(不考虑菱形继承的多继承,因为菱形继承需要用到虚继承,之后讨论)

原则:

  1.若子类新增虚函数,则放在声明的第一个父类的虚函数表中

  2.若子类重写了父类的虚函数,所有父类的虚函数表都要改变

  3.内存布局中,父类按照其声明顺序排列

#include <iostream>
using namespace std; class Base1
{
public:
virtual void fun1() {}
private:
int m_base1;
}; class Base2
{
public:
virtual void fun1() {}
virtual void fun2() {}
private:
int m_base2;
}; class Derive : public Base1,public Base2
{
public:
void fun1() {}
virtual void fun3() {}
private:
int m_derive;
}; int main()
{
Base1 b1;
Base2 b2;
Derive d; cout <<"b1:" <<sizeof(b1) << endl; //虚表指针大小+sizeof(int)
cout << "b2:" << sizeof(b2) << endl; //虚表指针大小+sizeof(int)
cout <<"d:" << sizeof(d) << endl; //两个虚表指针大小+3*sizeof(int) return ;
}
/*
程序结果:
b1:8
b2:8
d:20
*/

简单虚继承

虚继承可以解决菱形继承的情况

原则:

  1.虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个新的虚函数指针(vptr)以及一张虚函数表,该vptr位于对象内存的前面(对比非虚继承:直接扩展父类虚函数表)

  2.虚继承的子类也单独保留了父类的vptr和虚函数表

  3.虚继承的子类有虚基类表指针(vbptr)

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

样例:

#include <iostream>
using namespace std; class Base
{
public:
virtual void fun1() {}
virtual void fun2() {}
private:
int m_base;
}; class Derive : virtual public Base
{
public:
void fun1() {}
virtual void fun3() {}
private:
int m_derive;
}; int main()
{
Base b;
Derive d;
return ;
}

菱形虚继承

菱形虚继承是多继承和虚继承的复合

内存模型如下:

C++对象模型:单继承,多继承,虚继承,菱形虚继承,及其内存布局图的更多相关文章

  1. C++的菱形继承会发生什么问题?如何解决?画出其内存布局图

    菱形继承问题样例: #include <iostream> using namespace std; class A { public: ; virtual int getx() { re ...

  2. 虚继承之单继承的内存布局(VC在编译时会把vfptr放到类的头部,这和Delphi完全一致)

    C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼.虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内 ...

  3. c++内存分布之虚函数(单一继承)

    系列 c++内存分布之虚函数(单一继承) [本文] c++内存分布之虚函数(多继承) 结论 1.虚函数表指针 和 虚函数表 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关.多一个父类,派生 ...

  4. 继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。

    本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了 应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候 ...

  5. c++内存分布之虚函数(多继承)

    系列 c++内存分布之虚函数(单一继承) c++内存分布之虚函数(多继承) [本文] 结论 1.虚函数表指针 和 虚函数表 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关.多一个父类,派生 ...

  6. 从汇编看c++中的虚拟继承及内存布局(二)

    下面是c++源码: class Top {//虚基类 public: int i; Top(int ii) { i = ii; } virtual int getTop() { cout <&l ...

  7. 从汇编看c++的虚拟继承以及其内存布局(一)

    先看第一种最简单的情形,所有类中没有任何虚函数的菱形继承. 下面是c++源码: class Top {//虚基类 public: int i; Top(int ii) { i = ii; } }; c ...

  8. 图说C++对象模型:对象内存布局详解

    0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...

  9. 好文章系列C/C++——图说C++对象模型:对象内存布局详解

    注:收藏好文章,得出自己的笔记,以查漏补缺!     ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...

随机推荐

  1. Chomp类游戏——必胜策略分析

    首先介绍一个重要定理——策梅洛定理(Zermelo) 策梅洛定理,表明在二人参与的游戏/博弈中,如果满足: --------游戏的步骤数有限 --------信息完备(二人都了解游戏规则,了解游戏曾经 ...

  2. HUSTOJ 有序表的最小和

    一次奇怪的AC经历...上周被这道题卡了3天... 传送门:http://oj.gdsyzx.edu.cn/problem.php?id=1475 题目描述 给出两个长度为n的有序表A和B,在A和B中 ...

  3. 17-Flutter移动电商实战-首页_楼层区域的编写

    1.楼层标题组件 该组件非常简单,只接收一个图片地址,然后显示即可: class FloorTitle extends StatelessWidget {  final String picture_ ...

  4. Good Article Good sentence HDU - 4416 (后缀数组)

    Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...

  5. springboot与ssm的差异性

    springboot简化了ssm的配置 将外部jar包改为内部pom.xml文件配置 同时 使用了多种注解来进行注解式的开发 [图1:springboot的一些依赖模块] 通过原springmvc机制 ...

  6. 洛谷P1352 没有上司的舞会题解

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  7. VS2017 远程调试linux(centos).net core程序(通过附加程序的方式)

    参考两位大神的帖子: https://blog.csdn.net/soband_xiang/article/details/82914195 https://blog.csdn.net/weixin_ ...

  8. Django 数据库与ORM

    一.数据库的配置 1 django默认支持sqlite,mysql, oracle,postgresql数据库.  <1> sqlite django默认使用sqlite的数据库,默认自带 ...

  9. Fluent Meshing生成interface

    源视频链接: https://pan.baidu.com/s/1St4o-jB5KRfN5dLsvRe_vQ 提取码: 9rrr

  10. SSM 实现支付宝支付功能(图文详解+完整代码)

    阅读本文大概需要 4 分钟. 前言 本教程详细介绍了如何使用ssm框架实现支付宝支付功能.本文章分为两大部分,分别是「支付宝测试环境代码测试」和「将支付宝支付整合到ssm框架」,详细的代码和图文解释, ...