C++单一、多重继承下的内存模型

一:C++单一继承下的内存模型:

a)、最简单的一种单一继承内存模型:基类及派生类中无virtual function member:

#include <iostream>
class Base
{
public:
    Base(char _x = ‘\0‘) :m_x(_x) {}
    ~Base() {}
private:
    char m_x;
};
class Derived :public Base
{
public:
    Derived(char _x = ‘\0‘,int _y = 0,int _s = 0) :Base(_x), m_y(_y),m_z(_s) {}
    ~Derived() {}
private:
    int m_y;
    int m_z;
};
int main()
{
    Derived d(‘A‘,20,30);
    return 0;
}

在MSVC2015 Debug ×86下,&d = 0x00eff88c;&d.m_x = 0x00eff88c;&d.m_y = 0x00eff890;&d.m_z = 0x00eff894;至于d.m_x为什么会占用4个字节空间大小,这个跟内存对齐有关,由此可见,在单一继承下且类中non-virtual function member时,在派生类中内存模型:地址由低到高,分别为:派生类对象中基类子对象数据成员地址(顺序由基类中数据成员申明先后有关)、派生类特有对象数据成员地址(同上);

b)、单一继承下有virtual function member情况下:

#include <iostream>
class Base
{
public:
    Base(char _x = ‘\0‘) :m_x(_x) {}
    virtual void Show() { std::cout<<"this is BaseClass"<<std::endl; }
    ~Base() {}
private:
    char m_x;
};
class Derived :public Base
{
public:
    Derived(char _x = ‘\0‘,int _y = 0,int _s = 0) :Base(_x), m_y(_y),m_z(_s) {  }
    virtual void Show() { std::cout << "this is Derived" << std::endl; }
    ~Derived() {}
private:
    int m_y;
    int m_z;
};
int main()
{
    Derived d(‘A‘,20,30);
    return 0;
}

同样是在上述环境下,取&d = 0x0133f730;&d.m_x = 0x00133f734;&d.m_y = 0x00133f738;&d.m_z = 0x00133f73c;发现&d!=&d.m_x,这是由于在这四个字节的内存空间当中,存放了指向virtual function table(此为一列表格(可将其理解为数组),此表格中存放的是类中virtual function地址,vptr指向第一个在类中申明的virtual地址)的地址vptr;由此可以看到,在单继承模型中,派生类对象的内存模型:地址由低到高,分别为:vptr所指向的地址,派生类对象中基类子对象数据成员地址(顺序由基类中数据成员申明先后有关)、派生类特有对象数据成员地址(同上);

二:C++多重继承下的内存模型:

这也是C++与其他Object-Oriented编程语言如:java,C#的一个很大的不同,在java和C#当中取消了多重继承,取而代之的是通过继承接口的方式实现一种多继承;

#include <iostream>
class Base1
{
public:
    Base1(char _x = ‘\0‘) :m_x(_x) {}
    virtual void Show() { std::cout<<"this is Base1Class"<<std::endl; }
    ~Base1() {}
private:
    char m_x;
};
class Base2
{
public:
    Base2(int _a = 0):m_a(_a) {}
    virtual void display() { std::cout << "this is Base2Class" << std::endl; }
private:
    int m_a;
};
class Derived :public Base1,Base2
{
public:
    Derived(char _x = ‘\0‘,int _a = 0,int _y = 0,int _s = 0) :Base1(_x), Base2(_a),m_y(_y),m_z(_s) {  }
    virtual void Show() { std::cout << "this is Derived inherited by Base1" << std::endl; }
    virtual void display() { std::cout << "this is Dervied inherited by Base2" << std::endl; }
    ~Derived() {}
private:
    int m_y;
    int m_z;
};
int main()
{
    Derived d(‘A‘,10,20,30);
    return 0;
}

内存地址分布如下:

此时可以看到,在派生类对象模型中,地址由低到高,分别为:在继承申明时,派生类中第一个基类子对象的vptr,派生类中第一个基类子对象的地址;派生类中第二个基类子对象的vptr,派生类中第二个基类子对象的地址....由此进行类推;

总结:从上述分析可知,在派生类对象的内存模型当中,地址从低到高,分别为:基类当中vptr所指向的地址-->派生类中基类子对象地址-->派生类vptr所指向的地址-->派生类中特有对象的地址:

值得一提的是在发生类似于菱形继承时,通过virtual 继承方式,对象的内存模型会更加复杂;

原文地址:https://www.cnblogs.com/xin-99/p/9495909.html

时间: 2024-10-14 00:53:19

C++单一、多重继承下的内存模型的相关文章

Java并发编程(四)Java内存模型

相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 前言 此前我们讲到了线程.同步以及volatile关键字,对于Java的并发编程我们有必要了解下Java的内存模型,因为Java线程之间的通信对于工程师来言是完全透明的,内存可见性问题很容易使工程师们觉得困惑,这篇文章我们来主要的讲下Java内存模型的相关概念. 1.共享内存和消息传递 线程之间的通信机制有两种:共享内存和消息传递:在共享内存的并发模型里,线程之间共享程序的

java内存模型详解

内存模型 (memory model) 内存模型描述的是程序中各变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节. 不同平台间的处理器架构将直接影响内存模型的结构. 在C或C++中, 可以利用不同操作平台下的内存模型来编写并发程序. 但是, 这带给开发人员的是, 更高的学习成本.相比之下, java利用了自身虚拟机的优势, 使内存模型不束缚于具体的处理器架构, 真正实现了跨平台.(针对hotspot jvm, jrockit等不同的

JVM内存模型及String对象内存分配

昨天看了一篇关于<Java后端程序员1年工作经验总结>的文章,其中有一段关于String和StringBuffer的描述,对于执行结果仍然把握不准,趁此机会也总结了下JVM内存模型. 1.JVM运行时数据区域 关于JVM内存模型之前也了解过一些,也是看过就忘,好记性比如烂笔头,记下来吧.参考此文章http://chenzhou123520.iteye.com/blog/1585224 图1 JVM运行时数据区域 (1).程序计数器(Program Counter Register): 程序计数

Java锁(一)之内存模型

想要了解Java锁机制.引发的线程安全问题以及数据一致性问题,有必要了解内存模型,机理机制了解清楚了,这些问题也就应声而解了. 一.主内存和工作内存 Java内存模型分为主内存和工作内存,所有的变量都存储在主内存中.每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量.不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要主内存来完成. 二.线程.工作内存和主内存 下面是

浅谈Java内存模型

Java内存模型虽说是一个老生常谈的问题 ,也是大厂面试中绕不过的,甚至初级面试也会问到.但是真正要理解起来,还是相当困难,主要这个东西看不见,摸不着.网上已经有大量的博客,但是人家的终究是人家的,自己也要好好的去理解,去消化.今天我也来班门弄斧,说下Java内存模型. 说到Java内存模型,不得不说到 计算机硬件方面的知识. 计算机硬件体系 我们都知道CPU 和 内存是计算机中比较核心的两个东西,它们之间会频繁的交互,随着CPU发展越来越快,内存的读写的速度远远不如CPU的处理速度,所以CPU

jvm系列(一)之内存模型

JVM内存结构 Java内存模型是指Java虚拟机的内存模型,我们来看下Java内存模型的图片: VM内存模型主要分为三块:Java 堆内存(Heap).方法区(Non-Heap).JMV栈(JVM Stack).本地方法栈(Native Method Stacks).程序计数器(Program Counter Register). Java堆(Heap) 对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块.Java堆是被所有线程共享的一块内存区域,在虚

【Java并发基础】Java内存模型解决有序性和可见性

前言 解决并发编程中的可见性和有序性问题最直接的方法就是禁用CPU缓存和编译器的优化.但是,禁用这两者又会影响程序性能.于是我们要做的是按需禁用CPU缓存和编译器的优化. 如何按需禁用CPU缓存和编译器的优化就需要提到Java内存模型.Java内存模型是一个复杂的规范.其中最为重要的便是Happens-Before规则.下面我们先介绍如何利用Happens-Before规则解决可见性和有序性问题,然后我们再扩展简单介绍下Java内存模型以及我们前篇文章提到的重排序概念. volatile 在前一

Netty源码分析--内存模型(下)(十二)

这一节我们一起看下分配过程 1 PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { 2 PooledByteBuf<T> buf = newByteBuf(maxCapacity); // 初始化一块容量为 2^31 - 1的ByteBuf 3 allocate(cache, buf, reqCapacity); // reqCapacity = 1024 进入分配

【c++工程实践】内存模型

0.文章内容简介 这篇文章主要来讨论C++对象在内存中的布局,属于第二个概念的研究范畴.而C++直接支持面向对象程序设计部分则不多讲.文章主要内容如下: 虚函数表解析.含有虚函数或其父类含有虚函数的类,编译器都会为其添加一个虚函数表,vptr,先了解虚函数表的构成,有助对C++对象模型的理解. 虚基类表解析.虚继承产生虚基类表(vbptr),虚基类表的内容与虚函数表完全不同,我们将在讲解虚继承时介绍虚函数表. 对象模型概述:介绍简单对象模型.表格驱动对象模型,以及非继承情况下的C++对象模型.