第3章 Data语意学
在C++中经常会遇到一个类的大小问题,关于一个类的大小一般受到三个方面的影响。
- 语言本身所造成的额外负担,如在虚拟继承中会遇到如派生类中会包含一个指针指向base class subobjec,这样会造成内存的额外负担。
- 编译器对于特殊情况所提供的的优化。如果编译器不提供优化,则会在一个空的基类中会形成至少一个char类型的内存空间,传统上这一个char类型的空间会被放在该类内存的固定尾部,但是有些编译器会提供优化的策略,在空类型中不会生成这一个char成员对象的空间。
- Alignment的限制。如果一个中含有虚函数,其中如果包含一个char类型的函数成员,则会发生内存空间对其的情况,从而出现sizeof class_name = 8的情况,相当于struct中的内存对齐。
3.1 Data Member的绑定
在类中如果有一个函数成员的名称和一个全局变量的名称相同,在类内的某些函数对其进行参阅(取用)操作,相信很多人会说该操作是对类内成员的操作,对于今天的编译器来说答案是正确,但是在很早的时候,这个操作是针对的global x object的操作。当然对于这种在当时的情况下出现了两种防御措施。
- 把所有的数据成员放在类的声明起头处,以确保正确的绑定:
class X{
float x, y, z;
public:
float get_X(){return x}
}
2. 把所有的内联函数不管大小都放在类声明之外。
class X{
float x, y, z;
public:
float get_X(){}
}
inline float get_X(){
return x;
}
上面的情况在C++2.0之后就已经消失了,但是关于成员函数的形参中关于类型的操作应该加以注意如:
typedef int length;
class Point3d{
void numble(length val){_val = val}//此处的length为int
length numble(){return _val} //此处的length为int
private:
typedef length float;
length _val;
};
在这种情况下以上两种防御型风格仍然需要。
3.2 Data Member的布局
非静态成员的顺序和声明的顺序一样(同一访问权限中(public, protected, private)较晚出现的成员在类对象的较高的地址处),静态成员不会放在一个对象的布局之中。
3.3 Data Member的存取
1. 静态成员
class_name::static_data_member;
class_obj.static_data_member;
2. 非静态成员
Point3d Point3d::translate(const Point3d &pt){
x += pt.x;
y += pt.y;
z += pt.z;
}
将被转化为
Point3d Point3d::translate(const Point3d &pt){
this->x += pt.x;
this->y += pt.y;
this->z += pt.z;
}
关于取地址操作
origin._y = 0;
&origin._y的操作为&origin + (&origin._y - 1)
在类内声明的变量只会按照声明顺序来进行安排其内存地址如:
#include<stdio.h>
//#include<string.h>
#include<string>
#include<windows.h>
class A;
void p_printf(); void print(char s[], int *b){
char szbuffer[] = {};
wsprintf(szbuffer, s, b);
printf(szbuffer);
} class A{ void friend print(char, A *);
void friend p_print();
public:
int public_A;
protected:
int protected_A;
private:
int private_A; public:
int public_B;
protected:
int protected_B;
private:
int private_B; }; void p_print(){
A a;
printf("the a address is %#x\n\0", &a);
print("the a.public_A address is %#X\n\0", &a.public_A);
print("the a.protected_A address is %#X\n\0", &a.protected_A);
print("the a.private_A address is %#X\n\0", &a.private_A);
print("the a.public_B address is %#X\n\0", &a.public_B);
print("the a.protected_B address is %#X\n\0", &a.protected_B);
print("the a.private_B address is %#X\n\0", &a.private_B); } int main(void){ p_print(); } 输出为:
the a address is 0x28fef8
the a.public_A address is 0X28FEF8
the a.protected_A address is 0X28FEFC
the a.private_A address is 0X28FF00
the a.public_B address is 0X28FF04
the a.protected_B address is 0X28FF08
the a.private_B address is 0X28FF0C Process returned (0x0) execution time : 0.021 s
Press any key to continue.
3.4 继承与数据成员
1. 只继承无多态

这是因为在进行向上转换的时候采用memberwise拷贝,如果不各自对其,当由基类向派生类拷贝时容易出现

2. 加上多态
多态作为C++的类的三大特性(封装,继承,多态),在内存中的布局为继承体系中每个类内存对其后的按照继承顺序叠加在一起,最后是该类自身的数据成员,由于含有虚函数,所以会产生一个虚函数表,至于虚函数指针(一个指向虚函数表的指针)(C++标准对虚函数指针的存放位置并没有严格规定,但是编译器一般情况是放在一个类的头部或者是尾部)。

3. 多重继承
如上所说,按照继承顺序进行叠加数据成员,每个类的自身虚函数指针仍然在自己类的相应部分。
4. 虚拟继承
在类的继承体系中,有的时候会出现某几个父类自于继承自同一个base class,如下图所示,为避免空间的浪费,采用虚拟继承

使得继承模型变为

但是在这种模型设计过程中发现会出现随着继承类的增加会增加指向虚拟类的指针内存负担,从而出现将这些指针转移至虚函数指针在-1处添加共享类的偏移地址,0处代表type_info for class, 正值为该类的virtual func的函数地址,如:

第3章 Data语意学的更多相关文章
- 第4章 Function语意学
第4章 Function语意学 目录 第4章 Function语意学 4.1 Member的各种调用方式 Nonstatic Member Function(非静态成员函数) virtual Memb ...
- 第 7 章 Data 类型
目录 第 7 章 Data 类型 一.创建方式 二.转时间戳 其他 第 7 章 Data 类型 @(es5) 参考了: 阮一峰javascript的标准.<javascript高级教程> ...
- 【C++对象模型】第六章 执行期语意学
执行期语意学,即在程序执行时,编译器产生额外的指令调用,确保对象的构造,内存的释放,以及类型转换与临时对象的生成的安全进行. 1.对象的构造和析构 对于类对象的构造,一般在定义之后则开始内部的构造过程 ...
- 《深度探索C++对象模型》第二章 | 构造函数语意学
默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一 ...
- 《深度探索c++对象模型》chapter3 Data语意学
一个空的class:如 class X{} ; sizeof(X)==1; sizeof为什么为1,他有一个隐晦的1 byte,那是被编译器安插进去的一个char,这使得class2的两个object ...
- data语意学
引例: class X{}; class Y:public virtual X{}; class Z:public virtual X{}; class A:public Y,public Z{}; ...
- c++ data语意学
Data Member的绑定 extern float x; class Point3d { public: point3d(); //问题:被传回和被设定的x是哪一个x呢? float X() c ...
- 《深度探索C++对象模型》笔记——Data语意学
Data Member的绑定 inline member functin躯体之内的一个data member绑定操作会在整个class声明完成之后才发生. argument list中的名称还是会在它 ...
- 【C++】深度探索C++对象模型读书笔记--Data语意学(The Semantics of data)
1. 一个空类的大小是1 byte.这是为了让这一类的两个对象得以在内存中配置独一无二的地址. 2. Nonstatic data member 放置的是“个别的class object”感兴趣的数据 ...
随机推荐
- .NET快速开发平台免费版预发布
自己团队开发的一套软件,可通过配置完成列表.表单.流程等的快速开发,因项目原因有一段时间没更新了,准备发出来希望能帮助更多企业快速实现信息化. 该软件主要应用的技术有如下: 1.存储:采用SqlSer ...
- nginx + gunicorn + flask项目发布
程序安装(linux mint) gunicorn安装:pip install gunicorn nginx安装:sudo apt-get install nginx 配置 nginx默认配置信息在/ ...
- [Oracle][DATAGUARD] PHYSICAL STANDBY环境里,使用CATALOG管理Primary和Standby
1.先使用控制文件构筑好PHYSICAL STANDBY环境(Primary:Single 11.2.0.4,Standby Single 11.2.0.4) 2.构筑好Catalog用的服务器(Ca ...
- Cowboy http服务器 websocket
一.基础介绍 cowboy是一个小巧.快速.模块化的http服务器,采用Erlang开发.其中良好的clean module使得我们可以扩展到多种网络协议之中,cowboy自带的有tcp和ssl,而也 ...
- python识别图片中的代码。
在看并发编程网的时候,有些示例代码是以图片的形式出现的,要是此时自己想复制下来的话,只能对着图片敲了,很不爽,于是搜了一下识别图片的网站,有! 把图片上传上去解析,下来txt文本,打开一看,大部分能解 ...
- css flex布局,小程序flex布局,垂直居中完美解决
flex弹性布局,很好的解决了垂直居中的问题,上代码: wxml: <view class='container'> <view class='item item1'>item ...
- Problem E: 平面上的点和线——Point类、Line类 (V)
Description 在数学上,平面直角坐标系上的点用X轴和Y轴上的两个坐标值唯一确定,两点确定一条线段.现在我们封装一个“Point类”和“Line类”来实现平面上的点的操作. 根据“append ...
- Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array (简单DP)
题目:https://codeforces.com/contest/1155/problem/D 题意:给你n,x,一个n个数的序列,你可以选择一段区间,区间的数都乘以x,然后求出最大字段和 思路: ...
- 使用IdentityServer4,在一个ASPNetCore项目中,配置oidc和api的AccessToken两种认证授权
1.配置两种认证方式 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(op ...
- Can DBC 文件翻译,不是很标准,凑合看还可以
1 引言 DBC文件描述单个CAN网络的通信.这个信息足以监测和分析网络并模拟不是物理可用的节点(剩余的总线模拟). DBC文件也可以用来开发电子控制单元的通信软件,该控制单元应该是CAN网络的一部分 ...