关闭

C++对象在内存中的分布

306人阅读 评论(0) 收藏 举报
分类:


C++通过class的pointers和references来支持多态,这种程序风格就成为“面向对象”。


一、C++对多态的支持的三种方式

1.把一个派生类指针隐式转换成一个基类指针

ex: shape *ps = new circle();

2.经由virtual function机制

ex: ps->rotate();

2.经由dynamic_cast 和typeid运算符

ex:if(circle *pc = dynamic_cast<circle*>(ps)){...}


二、class object的大小包含三个部分

1.nonstatic data members的总和大小

2.字节对齐产生的大小

3.对virtual机制的支持产生的额外负担


三、示例

base class

#include <string>
using namespace std;
class ZooAnimal  
{
public:
	ZooAnimal(string _name);
	virtual ~ZooAnimal();
	virtual void rotate();

protected:
	int loc;
	string name;
};

derived class

#include "ZooAnimal.h"

class Bear : public ZooAnimal  
{
public:
	Bear();
	Bear(string _name);
	virtual ~Bear();
	void rotate();
	virtual void dance();
protected:
	enum Dances{
		FIRST_DANCE,
		SECOND_DANCE
	};
	Dances dances_known;
	int cell_bolock;
};
测试函数:

#include "Bear.h"
#include "ZooAnimal.h"
int main(int argc, char* argv[])
{
	ZooAnimal za("Zoey");
	ZooAnimal *pza = &za;
	printf("size of ZooAnimal = %d\n",sizeof(ZooAnimal));

	Bear b("Yogi");
	printf("size of Bear = %d\n",sizeof(Bear));
	Bear *pb = &b;
	ZooAnimal *pz = &b;
	Bear &rb = *pb;
	printf("Bear created!\n");
	return 0;
}

在内存中的布局:




分析:

sizeof(ZooAnimal):__vfptr(4)+loc(4)+npos(4)+__Ptr(4)+_Len(4)+_Res(4)=24个字节

sizeof(Bear):sizeof(ZooAnimal)+dances_known(4)+cell_bolock(4) = 32字节


Data语意学


C++的非static 成员变量在内存中的存储之所以要进行边界对齐,原因之一是考虑了需要避免在派生类之间复制的时候产生意向之外的内存覆盖,而进行边界对齐,就可以避免这个问题。


为了拓展性,可以在基类中提供一个virtual function接口。(只不过这样的话,每一个derived class将会继承一个基类的vptr member,多一个virtual table,此外virtual member function的调用也会变得复杂,因此需要权衡)。

继承的这个虚函数表指针在vc6里面是放在整个内存块的前端的。因为这对于“在多重继承下,通过class members 的指针调用virtual function,会带来好处,因为不用找这个指针。而放在后端则是在派生的时候可以与C语言的struct结构体进行兼容,这也是需要权衡的(不过这点好像和我们程序猿没什么事)”


虚拟继承和继承多个虚拟基类是不一样的,这个一定要明白虚拟继承的概念,很多最顶层基类只需要保持一份的情况下可以采用虚拟继承机制来实现。

不过这里有一个问题是,采用虚拟机制来控制的派生体系,每一个派生类都会背负一个基类的指针,并且是逐级向上存取,因此当继承层数过多的时候,就会产生效率问题。


Function语意学


成员函数和非成员函数都会被编译器进行name mangling转换成相同的形式

http://blog.csdn.net/xt_xiaotian/article/details/5431410

因为static member functions没有this指针这个特性。

所以不能够直接存取其class的nonstatic members---->要借助于具体对象

所以不能声明为const volatile virtual--->没有必要

所以不需要经由类对象来调用--->不依赖于类对象


virtual member function

对这样一个对虚拟函数z的调用:

ptr->z()

为了达到在执行期调用正确z()实体的目的,我们需要知道两件事

1.ptr的真实类型

2.z()实体的位置

在单继承下,virtual member function机制下,每一个object都会有一个vptr指向虚函数表,虚函数表中存放的就是对象的虚函数的函数实体,pure virtual funtion会占用一个slot,但pure virtual class 的派生类中,因为这个pure virtual function不存在,所以这个slot会用来放置其他virtual function


nonvirtual function的调用需要绑定到具体的class object对象上,这是因为nonvirtual function与对象无关的特性,会导致取到nonvirtual function的返回值是其在内存中的地址,而不是一个函数指针。(因此不能调用一个函数地址,也就需要绑定到具体对象上,将这个返回的内存地址转换成对象的函数指针了)

 

将被共享的数据放在base class中是一种正当的设计,但需要对这个成员初始化(在基类中提供带单数的 protected constructor,或是在每一个构造函数中初始化它)


 



0
0
查看评论

C++中函数在内存中的分布情况

现在我们写一个简单的代码,来看看他们在内存的变化是怎么样的: 函数bbb的地址是:0001 0000 0001 0111 0101 1001 0000 0100 十进制为269965572 函数cc c的地址是:0001 0000 0001 0111 0110 0000 1000 0...
  • s452195377
  • s452195377
  • 2017-09-17 18:36
  • 69

C++对象模型之简述C++对象的内存布局

在C++中,有两种类的成员变量:static和非static,有三种成员函数:static、非static和virtual。那么,它们如何影响C++的对象在内存中的分布呢? 当存在继承的情况下,其内存分布又是如何呢? 下面就一个非常简单的类,通过逐渐向其中加入各种成员,来逐一分析上述两种成员变量及...
  • ljianhui
  • ljianhui
  • 2015-05-22 02:28
  • 10054

C++语言--数组-6.1----数组在内存中的分布、数组名和函数、枚举常量

前言:2017年第一篇博客,祝大家新年快乐!! 1.数组在内存中的分布 我们来分析为什么a[0]=3?在C++中我们知道数组b中的最大下标角为9,当我们赋值给b[10]时,即使在数组b中下标10已经越界,但是 编译器还是会留存四个字节的地址给b[10]存放数值3,而a[0]的数组的存放地址恰...
  • wu371894545
  • wu371894545
  • 2017-02-05 15:42
  • 293

C++类中的对象在内存中的存放方式

现看下面的一个类 Class A { Pulic: A(); Int a; Int b; Int sun(int a1,int b1)// 计算 2 个数的和 { Result a1+b1; } }; 调用的时候声明一个...
  • lien0906
  • lien0906
  • 2015-04-30 17:59
  • 721

C++对象在内存中的布局(读汇编代码)

C++对象在内存中的布局 研究方法以及ARM调用规范 最近在对C++编写的SO库进行逆向,如果掌握了对象的布局,那么逆向也能轻松些,所以萌发了研究对象布局的想法。 本文采用的研究方法是:编写C++代码,用gcc编译。通过IDA查看编译后的代码,分析ARM汇编代码,总结出内存布局。由于能力有限,...
  • stillvxx
  • stillvxx
  • 2014-09-21 11:51
  • 1181

C++中如何在指定的内存中创建新对象

在Free store或者是heap中动态创建程序所需对象时,很多人都知道,用 new 就可以了。那么如何在指定的内存空间中创建对象?就比如要在0x320f8该内存地址上动态创建一个int类型,怎么破?C++提供了几种特点来方便实现在预先决定的内存位置构造一个对象的任务。在这些特点中,包括一个特殊形...
  • gao1440156051
  • gao1440156051
  • 2016-05-18 10:44
  • 1465

C++类的存储及类对象内存结构(整理)

本文分两部分,前半部分讲类的存储后半部分讲类的内存结构。 C++类的存储 c++中最重要的就是类,那么一个类的对象,它在内存中如何存储的?它占 内存中多少个字节? 首先确定类的构成: 1,数据成员:可以是内置类型,类类型。 2,函数成员:虚函数,非虚函数 1)数据成员 内置类型对齐原...
  • fenxinzi557
  • fenxinzi557
  • 2016-07-22 16:06
  • 4289

Java对象创建与内存分布

本文主要讲述Java对象在虚拟机中创建,分配内存,初始化的过程,以及分配内存,引用对象的几种常见方式。对象创建对象创建分为三部分,首先是类加载,接着是为对象分配内存,最后是初始化。
  • thesingularityisnear
  • thesingularityisnear
  • 2016-07-28 00:20
  • 841

C++中有三种创建对象 内存分配问题

我们都知道C++中有三种创建对象的方法,如下: #include using namespace std; class A { private: int n; public: A(int m):n(m) { } ~A(){} }; int main(...
  • mengfanteng
  • mengfanteng
  • 2016-04-09 16:54
  • 686

C++对象在内存中的存储

最近忽然迷惑,子类继承父类之后,子类对象在内存中的存储方式是怎样的。理论上上应该是虚函数表指针、父类变量、子类变量。父类变量存储时是否和子类变量一起实现内存对齐呢? 为了搞明白这个问题,做了如下实验。 编译环境:win32,VS2008,Version3.5 SP1 #include &quo...
  • linghaidong
  • linghaidong
  • 2016-01-02 17:36
  • 756
    个人资料
    • 访问:101877次
    • 积分:2149
    • 等级:
    • 排名:千里之外
    • 原创:101篇
    • 转载:7篇
    • 译文:16篇
    • 评论:8条
    最新评论