前言
一个c++类包含两种,一种是只包含普通成员函数的类,另一种是包含虚函数的类。
只包含普通成员函数的类
对于不含虚函数的类而言,成员函数可以被看作是类作用域的全局函数,不在对象分配的空间里。也就是说类中普通成员函数对类内存大小没有影响。
内存分布如下:
1)类的成员变量------------内存在栈上
2)类的成员指针变量------------指针变量在栈上
3)类的静态成员------------内存在静态区
4)类的成员函数------------普通成员函数,静态成员函数 都在代码区
5)类的引用变量------------共享初始化时的变量的地址 (引用变量的内存实际还是在栈)
6)类的const变量------------和常规变量一样 内存在栈 可以通过指针方式强行修改const变量的值,在类内部初始化的常量是运行时可以修改的
问题1:通过一个类对象调用成员函数,如果确定这个成员函数属于这个类?
答:对象调用成员函数时,在编译期,编译器就可以确定这些函数的地址,并通过传入this指针和其他参数,完成函数的调用,所以类中就没有必要存储成员函数的信息。
含有虚函数的类
如果一个类中含有虚函数的话,在类内存中一开始就会有一个vptr(虚指针)。这个虚指针指向一个虚表,虚表是由类中指向虚函数的指针构成的数组。vptr是在类的构造中被初始化,这是由系统决定的,我们无法改变。
类中成员变量的布局
1)成员变量在类中内存的先后顺序与其在类中被声明的先后顺序一致,也就是说先声明的变量在内存的前边。
2)类中成员变量初始化的先后顺序与其声明先后顺序一致,与构造中被初始化先后顺序无关。
3)如果类中含有虚函数,那么类中第一个位置的变量是vptr(虚函数表的地址)。
4)类大小的是在编译期间就被确定了,所以sizeof可以作用与一个类名。
示例1
一个空类的大小是1。
#include <iostream>
using namespace std;
class A
{
};
int main()
{
cout << sizeof(A) << endl;
system("pause");
return 0;
}
执行结果:1
示例2(win10 64位 + vs2015)
一个带有虚函数的类的大小 = 私有成员变量的大小 + 4(虚函数指针的大小)
#include <iostream>
using namespace std;
class A
{
public:
virtual void func1() {}
virtual void func2() {}
private:
int a; //4个字节
double b; //8个字节
};
int main()
{
cout << alignof(A) << endl; //alignof获取内存对齐的大小 为8
cout << sizeof(A) << endl;
system("pause");
return 0;
}
执行结果:24
解释:前面介绍过,一个带有虚函数的类,内存一开始是一个虚函数指针,用来指向虚函数表,大小为4。又因为alignof(A) = 8,即系统内存对齐的大小为8,故输出24。