C++ 入门 03 _类和对象(中)

类和对象(上)

[本节目标]

续:   把这个知识点单独列一篇博客是因为相对上一节, 这个知识点更加独立一些. 

1. 类的对象大小的计算

问题:  这是一个简单的类, 但是这个类中即有成员变量, 又有成员函数, 那么这个类的大小是多少?

 答案是一个字节. char _a的大小确实是一个字节, 那么PrintA()函数的大小去哪儿了呢, 难道函数不占空间么?

猜测一:   在类中的所有函数都以指针形式存放,  一个函数就是一个指针即4个字节或8个字节, 再加上各自的成员变量的类型大小, 以结构体内存规则对齐存放, 是这样么?

不是的,  每个对象中成员变量是不同的, 但是调用同一份函数, 什么意思呢, 假设Class A中有一个函数叫Add(), 接着Class A实例化了两个对象 object1 和object2 , 那么当你分别调用这两个函数中的Add()函数时, 这两个函数一样么?    其实你调用的是同一个函数. 如果按照猜测一的方式进行储存, 当一个类定义多个对象时, 每个对象中都在储存区中保存一份代码, 相同代码保存多次, 浪费空间!!!

猜测二: 类中只保存成员变量, 成员函数只保存一个函数名, 函数具体内容通过一个页表映射到存储区各个位置, 调用的时候再通过这个页表去找到具体的代码.

可以的, 这种存储方式在某些结构上正是如此应用的, 但是在类中,还不是这种方法, 此种方法暂略过不做讲解

猜测三: 类中只保存成员变量, 成员函数储存在公共代码区.  类中采用的方式正是猜测三, 接下去通过一段代码验证一下.

A1中有一个成员函数和一个成员变量char,  大小为1, 说明函数没存在对象i 中

A2中有一个成员变量char, 大小为1, 说明char是存在对象j 中得

 A3是一个空类, 但为了给对象k占位, 也存了一个字节

结论: 一个类的大小, 实际就是该类中成员变量之和, 当然也要进行内存对齐, 注意空类的大小, 空类比较特殊, 占位一个字节

C语言结构体内存对齐规则  复习:

1. 第一个成员在与结构体偏移量为0 的地址处.

2. 其他成员变量要对其某个数字(对齐数)的整数倍的地址处.

对齐数 = 编译器默认的一个对齐数 与 该成员大小的的较小值. VS一般默认是8

3. 结构体总大小为: 最大对齐数的整数倍, 如果不够,在计算时需要补齐

4. 如果是嵌套结构体, 嵌套的结构体对齐到自己的最大对齐数的整数倍 处, 结构体的整体大小是所有最大对齐数的整数倍

面试题:

1. 结构体怎么对齐?  为什么要进行内存对齐     

直接上代码,用图说话吧

这里如果不考虑结构体对齐规则的话, 直接计算结构体大小, 应该是int + char + int + int = 4+1+4 = 10.  

 当然, 结果肯定是不对的. 那么实际情况应该是怎么样的呢? 

这里如果没理解清楚的话, 那我们继续上图, 用图说话.

 看官们可以自行验证一下.

2. 如何让结构体按照指定的对齐参数进行对齐?

#pragma pack x (x为指定对齐数值) 举例如果x是4, 那么统一按照4个字节进行对齐,

还是上面那个例子

 

 按照之前计算应该为16个字节大小, 可是实际结果为10个字节,怎么算的呢?

对齐数现在为1, 即不需要为了对齐而进行占位了. 1 + 4 + 1+4 = 10

如果改成#pragma pack(2)呢?

 

 相信看到这里大家对于结构体对齐规则肯定搞懂了 ,  那么嵌套结构体应该如何计算呢?

也非常简单,  首先肯定是先计算最里面的那个结构体大小 . 然后再确定对齐数是多少, 

这种嵌套结构体的最大对齐数是取其成员最大类型的大小, 如下面代码

#include<iostream>
#include<vector>
struct S1 {
	char a;// 0
	double b;// 8-15
	short c[2];//16-19,因为double的8比short的2大,引用规则一
	//共24
};
struct S2 {
	struct S1 a;// , 0-23
	int b;//24-27
	char c;//28
	// 最后按S1的最大类型double的8字节对齐,因为double比S2的int和char字节数都大,最后
	//整个S2按照8字节对齐
};
int main() {
	using namespace std;
	cout << sizeof(S1) << " " << sizeof(S2) << endl;
}

就是max(sizeof(struct S1),sizeof(max_type_of_S2))

补充:关于#pragma pack(x)

编译器会自动优化, 比如说结构体中最大的成员变量是int, 4个字节 ,  你指定8 个字节对齐, 那么是无效的, 编译器判断最大的成员变量就是4个字节,将以4个字节规则进行对齐.

3. 什么是大小端? 如何测试某台机器是大端还是小端, 有没有遇到过要考虑大小端的场景

大小端是计算机储存数据的一种格式, 大端是数据的低地址存在高位, 小端是数据的低地址存在低位, 可以用代码测试

 解析 :  int类型i 的值是 1 ,   如果是大端存储 就是 : 0000 0000 0000 0001 , 如果是小端存储就是

1000 0000 0000 0000 .  取地址i , 然后强制转化成char* 类型, 再解引用, 因为char*类型解引用只访问1个字节,  赋值给c,  那么此时c如果是1就是小端模式,  如果是0就是大端模式

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值