【c++内存分布系列】单独一个类
首先要明确类型本身是没有具体地址的,它是为了给编译器生成相应对象提供依据。只有编译器生成的对象才有明确的地址。
一、空类
形如下面的类A,类里没有任何成员变量,类的sizeof值为1。
#include <cstdio> class A
{
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(A));//类型A的大小 A a;
A* pa = &a;
printf("%08x\n", pa);//对象a的地址 printf("%02x\n", *pa);//对象a的内容
}
windows输出:
1
0023fc9b
cc
这是因为编译器在编译时为类A插入了一个char型变量,以便确定类A的对象在内存的位置。插入的变量不进行初始化,所以看到内存中的内容为cc
二、包含成员函数但没有成员变量
只包含成员函数没有成员变量的类形式如下:
#include <cstdio> class A
{
public:
void fun(){};
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(A));//类型A的大小 A a;
A* pa = &a;
printf("%08x\n", pa);//对象a的地址 printf("%02x\n", *pa);//对象a的内容 void (A::*p)();
p = &A::fun;
printf("%08x\n", p);//成员方法fun的地址
}
windows的输出:
1
001aff23
cc
003211a4
因为成员函数有自己的地址,不随对象而变化,所以类型A的大小依然是1。查看内存003211a4有:
A::fun:
003211A4 E9 17 03 00 00 jmp A::fun (3214C0h)
直接跳转到3214c0h,再查看3214c0h有:
1: #include <cstdio>
2:
3: using namespace std;
4:
5: class A
6: {
7: public:
8: void fun(){};
003214C0 55 push ebp
003214C1 8B EC mov ebp,esp
003214C3 81 EC CC 00 00 00 sub esp,0CCh
即源码的汇编程序。到此应该可以理解为什么成员函数不需要随对象的生成而分配地址了。因为所有对象的方法对应的汇编执行都应该是一样的,所以存在一份足够了,不需要每个对象都重新分配该段代码的空间。
三、包含成员变量
类A包含成员变量形式如下:
#include <cstdio> class A
{
public:
int a;
void fun(){};
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(A));//类型A的大小 A a;
a.a = 0xaaaaaaaa;//给成员变量赋值
A* pa = &a;
printf("%08x\n", pa);//对象a的地址 printf("%08x\n", *pa);//对象a的内容 void (A::*p)();
p = &A::fun;
printf("%08x\n", p);//成员方法fun的地址
}
windows输出:
4
0019fc9c
aaaaaaaa
00b411a4
由于包含成员变量,类A生成的每个对象的成员变量值不一定相同,所以成员变量要随每个对象的生成分配自己的空间。此例的成员变量为int型,所以sizeof类A的值就为类A成员变量占用内存大小的总和,此例为4。如果有更多的成员变量,sizeof的值则为他们的和,内存也依次为他们的值排列,这里就不举例了。查看对象a的内容为0xaaaaaaaa,也验证了该地址存放的是成员变量的值。
四、包含静态方法和静态成员变量
#include <cstdio>
class A
{
public:
int a;
void fun(){};
static int sa;
static void sfun(){};
}; int A::sa = 0xbbbbbbbb;//给静态成员变量赋值 int main(int argc, char** argv)
{
printf("%d\n", sizeof(A));//类型A的大小 A a;
a.a = 0xaaaaaaaa;//给成员变量赋值
A* pa = &a;
printf("%08x\n", pa);//对象a的地址 printf("%08x\n", *pa);//对象a的内容 void (A::*p)();
p = &A::fun;
printf("%08x\n", p);//成员方法fun的地址 printf("%08x\n", &(A::sa));//静态成员变量的地址
printf("%08x\n", A::sa);//静态成员变量的值 printf("%08x\n", A::sfun);//静态方法的地址
}
windows输出:
4
001ffaa0
aaaaaaaa
012011a4
01207000
bbbbbbbb
012011d1
很简单,大家都知道,静态方法和静态变量都有自己的地址,当然也就不会随对象的生成而重新分配,所以sizeof(A)的值依然是4。
去内存0x01207000查看静态成员地址的内容为0xbbbbbbbb,ok没问题,再来看看静态方法内存对应的内容:
10: static int sa;
11: static void sfun(){};
01201580 55 push ebp
01201581 8B EC mov ebp,esp
01201583 81 EC C0 00 00 00 sub esp,0C0h
没错,代码对应的汇编。这下就清晰了。
五、包含虚函数
加入两个虚函数,其他代码不变。
#include <cstdio> class A
{
public:
int a;
void fun(){};
static int sa;
static void sfun(){};
virtual void vfun1(){};
virtual void vfun2(){};
}; int A::sa = 0xbbbbbbbb;//给静态成员变量赋值 int main(int argc, char** argv)
{
printf("%d\n", sizeof(A));//类型A的大小 A a;
a.a = 0xaaaaaaaa;//给成员变量赋值
A* pa = &a;
printf("%08x\n", pa);//对象a的地址 printf("%08x\n", *pa);//对象a的内容 void (A::*p)();
p = &A::fun;
printf("%08x\n", p);//成员方法fun的地址 printf("%08x\n", &(A::sa));//静态成员变量的地址
printf("%08x\n", A::sa);//静态成员变量的值 printf("%08x\n", A::sfun);//静态方法的地址
}
windows下输出:
8
0021fa7c
0125574c
012511d6
01257000
bbbbbbbb
01251208
之所以加入两个虚函数,是为了验证编译器只生成了一个虚表,续表的概念不明白的话要查下。也正是因为加入了虚表,内存增加了4,即sizeof(A)的结果变成了8。查看对象a的内存:
0021FA7C 4C
0021FA7D 57
0021FA7E 25 01 AA AA AA
0021FA83 AA
除了0xaaaaaaaa还新增了0x0125574c,这就是虚表的地址。查看该地址内容:
A::`vftable':
0125574C 27
0125574D 11 25 01 86 11 25
01255753 01
包含了两个地址,分别为:0x01251186,0x01251127。这两个地址就是对应两个虚函数,下面只拿其中一个来分析,另一个一样。查看0x01251186:
A::vfun2:
01251186 E9 25 05 00 00 jmp A::vfun2 (12516B0h)
此处直接跳转到vfun2的执行处,内容如下:
13: virtual void vfun2(){};
012516B0 55 push ebp
012516B1 8B EC mov ebp,esp
012516B3 81 EC CC 00 00 00 sub esp,0CCh
012516B9 53 push ebx
没错,vfun2的汇编。
至此一个类的内存所有情况都分析到了,如果该类中包含其他类的对象,那么先计算那个对象的内存占用大小,然后把它当做普通的成员变量看待就可以了。
【c++内存分布系列】单独一个类的更多相关文章
- 【c++内存分布系列】虚基类表
虚基类表相对于虚函数表要稍微难理解些,故单独提出来. 虚函数表是在对象生成时插入一个虚函数指针,指向虚函数表,这个表中所列就是虚函数. 虚基类表原理与虚函数表类似,不过虚基类表的内容有所不同.表的第一 ...
- 【c++内存分布系列】单继承
父类包括成员函数.静态函数.静态方法,子类包括成员函数.静态函数.静态方法的情况与一个类时完全一致,这里就不做分析了.子类单独包含虚函数时继承无关,也不做分析了. 一.父类子类都为空 #include ...
- c++内存分布之虚函数(单一继承)
系列 c++内存分布之虚函数(单一继承) [本文] c++内存分布之虚函数(多继承) 结论 1.虚函数表指针 和 虚函数表 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关.多一个父类,派生 ...
- c++内存分布之虚析构函数
关于 本文代码演示环境: VS2017+32程序 虚析构函数是一种特殊的虚函数,可以知道,虚函数影响的内存分布规律应该也适用虚析构函数.看看实际结果. Note,一个类中,虚析构函数只能有一个. 本文 ...
- C++对象内存分布(3) - 菱形继承(virtual)
1.前言 本篇文章的全部代码样例.假设是windows上编译执行.则使用的是visual studio 2013.假设是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i ...
- C++对象内存分布详解(包括字节对齐和虚函数表)
转自:https://www.jb51.net/article/101122.htm 1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数 ...
- VC++中的类的内存分布(上)(通过强制转换,观察地址,以及地址里的值来判断)
0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC ...
- C++类内存分布
http://www.cnblogs.com/jerry19880126/p/3616999.html#undefined 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看 ...
- C++ 类的内存分布
C++类内存分布 转自:http://www.cnblogs.com/jerry19880126/p/3616999.html 先写下总结,通过总结下面的例子,你就会明白总结了. 下面总结一下: ...
随机推荐
- Python-aiohttp百万并发
http://www.aikaiyuan.com/10935.html 本文将测试python aiohttp的极限,同时测试其性能表现,以分钟发起请求数作为指标.大家都知道,当应用到网络操作时,异步 ...
- 递归算法实现10进制到N进制的转换
#include<iostream> using namespace std; int BaseTrans(int data,int B){ int s; ) ; //结束递归算法 s=d ...
- Rsyslog配置
http://blog.itpub.net/30015039/viewspace-1457009/
- POJ 3440 Coin Toss(求概率)
题目链接 题意 :把硬币往棋盘上扔,分别求出硬币占1,2,3,4个格子的时候的概率. 思路 : 求出公式输出,不过要注意输出格式,我还因为输入的时候用了int类型错了好几次..... #include ...
- Bessie的体重问题
P1028 Bessie的体重问题 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 USACO OCT09 8TH 描述 Bessie像她的诸多姊妹一样,因 ...
- ASP.NET中App_Code,App_Data等文件夹的作用
http://www.cnblogs.com/shiyu007/archive/2007/12/04/982264.html 1. Bin文件夹 Bin文件夹包含应用程序所需的,用于控件.组件或者需 ...
- Hibernate逍遥游记-第15章处理并发问题-002悲观锁
1. 2. hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.connection.driver_class=com.mys ...
- Struts2 Package
package 元素的所有属性及对应功能: Attribute Required Description name yes key to for other packages to reference ...
- HDU4389:X mod f(x)(数位DP)
Problem Description Here is a function f(x): int f ( int x ) { if ( x == 0 ) return 0; return f ( x ...
- Xml文件保存值不能及时更新
今天在Xml文件中修改了一个值,调试时,发现读取的不是最新值.经过各种调试,还是不能解决.只好把文件项目给编译了一遍,在调试时,把在及时窗口,把变量值给改了一下啊,就是可以读到最新配置了.停止程序,在 ...