静态成员未初始化或者未调用(当然静态成员必须类外初始化才能调用)是不占内存的。静态成员不占类或结构体的内存
静态成员函数同样只声明未定义同样不占内存
指针在64位机8个字节,32位机4个字节,
可以参考指针大小与32位、64位系统
// vector::emplace_back
#include
#include
struct dddd{
int x;
int y;
static int z;
dddd(int a,int b):x(a),y(b){}
void dd(){}
static int cc();
};
int dddd::cc(){}
int dddd::z=0;
int main ()
{
/*std::vector myvector;
myvector.emplace_back (100,200);
std::cout << "myvector contains:";
/*for (auto& x: myvector)
std::cout << ' ' << x.second;
std::cout << '\n';*/
dddd::z=0;
std::cout<<sizeof(dddd)<<std::endl;
return 0;
}
结构体存在内存对齐,类(对象)也如此,甚至于所有变量在内存中的存储也有对齐一说(只是这些对程序员是透明的,不需要关心)。实际上,这种对齐是为了在空间与复杂度上达到平衡的一种技术手段,简单的讲,是为了在可接受的空间浪费的前提下,尽可能的提高对相同运算过程的最少(快)处理。
先看以下程序
#include
union ss
{
int a;
char b;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//一个字节,补齐3个字节
ss aa;//4个字节
char temp3;//一个字节
char temp4;//一个字节,补齐两个字节
};
int main()
{
printf("%d",sizeof(MyStruct));
return 0;
}
对齐规则是按照成员的声明顺序,依次安排内存,对齐字节数为最大成员变量的字节大小,偏移量为最大成员变量的字节数的整数倍,在这个程序中对齐字节数为4
#include
union ss
{
int a;
double b;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//1个字节,对齐是8个字节,还需3个字节补齐
ss aa;//8个字节
char temp3;//1个字节
short temp4;//2个字节,补齐还需要5个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}
aa是最大字节8个,所以temp2开始补齐,所以总的为24
#include
union ss
{
int a;
double b;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//1个字节
char temp3;//1个字节,对齐是8个字节,还需2个字节补齐
ss aa;//8个字节
short temp4;
short temp5;
short temp6;
short temp7;
short temp8;//2个字节,补齐还需要6个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}
大小为32
#include
union ss
{
int a;
double b;
};
struct student
{
int name;
char sex;
double num;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//1一个字节,补齐3个字节
ss aa;//8个字节
char temp3;//一个字节
short temp4;//2个字节,补齐5个字节
student people;//16个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}
大小为40;
此时需要注意的是,对齐字节数8个字节,而不是16个字节。student people 对象内部先进行一次对齐,然后如果如果是外面对齐字节数的整数倍就不需要
#include
union ss
{
int a;
double b;
};
struct student
{
//int name;
//char sex;
int num;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//1一个字节,补齐3个字节
ss aa;//8个字节
char temp3;//1个字节
short temp4;//2个字节
student people;//4个字节,补齐一个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}
大小为24
空结构体大小为1
c++要求每个实例在内存中都有独一无二的地址。空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。结构体在是特殊的类
类只用计算成员变量与指针的大小,空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。
静态成员变量和静态成员函数都是类的所有对象共享的,静态成员变量存放在全局存储区,静态成员变量和静态成员函数在编译时就已经在全局区分配的内存。
#include
using namespace std;
class student
{
static int b;
static void func();
};
int main()
{
cout << sizeof(student) << endl;
return 0;
}
大小为1
class CBase
{
public:
CBase(void);
virtual ~CBase(void); //1个字节
private:
int a;
char *p; //1个字节补齐3个字节
};
大小为12,虚函数会产生一个虚函数指针,指针大小为4个字节,虚函数指针指向虚函数表。但是并不是每一个虚函数都会产生一个虚函数指针,同一个类中的所有虚函数只会产生一个虚函数指针。
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;//4个字节
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
大小为12派生类会继承父类的成员变量和虚函数等,所以子类的内存大小是在父类的内存大小的基础上加上自己增加的内存大小。
G++实测24个字节,我的理解是虚函数指针8个字节(实测只有虚函数的情况下),int,char补齐8个字节,继承按道理讲是直接16+4=20个字节,我的理解是补齐4个字节,所以24个字节,实测也是这样的
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;//4个字节
int c;//4个字节
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
24个字节
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;//4个字节
int c;//4个字节
int a;//4个字节,补齐4个
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
32个字节
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;
public:
void fly();
virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
16个,g++64位机实测24
测试如下代码:发现原因,虚函数指针在64位机8个字节,在32位机是4个字节,不论有几个虚函数但只有一个虚函数指针,所以即使存在3个虚函数大小还是8或4;
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void CC(){};
};
class student1
{
//int d;
public:
void CC(){std::cout<<"1";};
virtual void eat(){};
virtual void at(){};
virtual void t(){};
};
int main()
{
student * aa;
student1 bb;
//aa=&bb;
//aa->CC();
std::cout<<sizeof(student1)<<endl;
return 0;
}
64位机G++测试结果为8
#include
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void CC(){};
};
class student1:public student
{
//int d;
public:
void CC(){std::cout<<"1";};
virtual void eat(){};
virtual void at(){};
virtual void t(){};
};
int main()
{
student * aa;
student1 bb;
//aa=&bb;
//aa->CC();
std::cout<<sizeof(student1)<<endl;
return 0;
}
G++64位机测试为16,int d加上 测试为24
可以看出按照虚指针的大小进行补齐;
问题:子类声明了一个虚函数且该虚函数是父类中没有的虚函数为什么子类没有新产生一个虚函数指针。
这个涉及到内存布局问题,首先是基类产生了一个虚函数指针,这个虚函数指针会指向虚函数表,表中存放的是基类的虚函数。子类也会继承到这个虚函数指针,虚函数指针指向虚函数表,表中先是存放基类的虚函数,再存放子类的基函数,如果子类重载了父类的某些虚函数,那么新的虚函数将虚函数表中父类对应的虚函数覆盖
虚继承——空类
#include
using namespace std;
class student
{
};
class student1: virtual student
{
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
g++测试为64位机8个字节,如上虚指针的红字部分
#include
using namespace std;
class student
{
int a;
char c;
//static int b;
public:
//static void func();
virtual void fly();
};
class student1: virtual student
{
int d;
public:
void fly();
//virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
G++测试为32;按8位补齐因为虚继承会再产生一个虚函数指针,去指向对应的基类,防止子类继承多个一样的基类,造成资源浪费
#include
using namespace std;
class student
{
int a;
char c;
//static int b;
public:
//static void func();
virtual void fly();
};
class student1: virtual student
{
int d;
public:
void fly();
virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}
64位机G++测试为32;按8位补齐。此时是子类声明的虚函数是父类没有的,则此时子类会再产生一个虚函数指针,如果此时子类的所有虚函数都是继承自基类的,则不会产生虚函数指针。
参考:struct和class内存大小的计算
C++中 类 和 结构体所占内存大小