2.2 C++对象结构的发展和演化-C++类的对象模型分析

一、非静态成员变量(普通成员变量)跟着类的对象走(存在对象内部),也就是每个类对象都有自己的成员变量。

示例代码:

#include <iostream>
using namespace std;
class A
{
public:
	int a = 100; 
};

//类对象所占的空间
int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


调试:

找到对象 aobj的地址:

黏贴到内存中:

内存地址  64 00 00 00 ,这四个字节即为 对象aobj的内存地址,十六进制 64 转化为十进制为数值 100,即    int a = 100; 

 

二、静态成员变量跟类的对象没有什么关系,所以肯定不会保存在对象内部,是保存在对象外面(表示所占用的内存空间和类对象无关)的。

示例代码:

#include <iostream>
using namespace std;
class A
{
public:
	static int a; 
	static int b;
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


输出:

三、 成员函数:不管静态的还是非静态的,全部保存在类对象之外。所以不管几个成员函数,不管是否是静态的成员函数,对象的sizeof()都是不增加的。

示例代码:

#include <iostream>
using namespace std;
class A
{
public:
	static void sfunc() {};  //静态成员函数
	void myfunc() {};   //普通成员函数
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


输出:

 

四、虚函数:不管几个虚函数,sizeof()都是多了4个字节。

示例代码:

#include <iostream>
using namespace std;
class A
{
public:
	virtual void vfrandfunc1() {}; //虚函数 1
	virtual void vfrandfunc21() {}; //虚函数2 
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


 输出:

结果分析: 

    (4.1)类里只要有一个虚函数(或者说至少有一个虚函数),这个类 会产生一个 指向 虚函数 的指针。
      有两个虚函数,那么这个类 就会产生两个指向虚函数的指针。
    类本身  指向虚函数的 指针(一个或者一堆)要有地方存放,存放在一个表格里,这个表格我们就称为“虚函数表(virtual table【vtbl】)”;
     这个虚函数表一般是保存在可执行文件中的,在程序执行的时候载入到内存中来。
    虚函数表是基于类的,跟着类走的;

    (4.2)说说类对象,这四个字节的增加,其实是因为虚函数的存在;因为有了虚函数的存在,导致系统往类对象中添加了一个指针,
     这个指针正好指向这个虚函数表,很多资料上把这个指针叫vptr;这个vptr的值由系统在适当的时机(比如构造函数中通过增加额外的代码来给值);

五、小结:(对于类中)

    (1)静态数据成员不计算在类对象sizeof()内;
    (2)普通成员函数和静态成员函数不计算在类对象的sizeof()内
    (3)虚函数不计算在类对象的sizeof()内,但是虚函数会让类对象的sizeof()增加4个字节以容纳虚函数表指针。
    (4)虚函数表[vtbl]是基于类的(跟着类走的,跟对象没关系,不是基于对象的);
    (5)如果有多个数据成员,那么为了提高访问速度,某些编译器可能会将数据成员之间的内存占用比例进行调整。(内存字节对齐)

例如:

class A //由于字节对齐,共占用8个字节
{
public:
	char a; //1字节,由于字节对齐,编译器会分配给4个字节
	int b;  //4字节
};


  (6)不管什么类型指针char *p,int *q;,该指针占用的内存大小是固定的
例如:

int ilen2 = sizeof(char *); //占用4个字节(linux下占用8个字节)
int ilen3 = sizeof(int *);  //占用4个字节

六、编程实验:

#include <iostream>
using namespace std;

class myobject
{
public:
	myobject() {};//构造函数,不占对象空间
	virtual ~myobject() {}; //析构函数,产生虚函数表,占4个字节       
	float getvalue() const //普通成员函数不占对象字节
	{
		return m_value;
	}

	static int s_getcount() //静态成员函数,不占字节 
	{
		return ms_scount;
	}

	virtual void vfrandfunc() {}; //虚函数,只算一个虚函数的4字节(析构函数) 

protected:
	float m_value; //普通成员变量,占4字节
	static int ms_scount; //静态成员变量,不占字节,跟着类走
};

int main()
{
	
	myobject obj;
	int ilen = sizeof(obj);
	cout << ilen << endl; 
	getchar();
	return 0;
}

输出:

 

结果分析:

   成员变量m_value占4字节,虚函数表指针占4字节。

七、总结类对象大小的组成:
    (1)非静态成员变量所占的内存总量以及这些成员变量之间内才能字节对齐所额外占用的内存;
    (2)若有虚函数,则会产生虚函数表指针(vptr)。

八、C++类的对象模型:



 

本文为听课笔记,课程出处:

https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-18601780182.25.19293d232GUXy4&id=579444695287

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值