一.成员函数的储存方式
用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如下图所示。
我们可以看出这样不仅麻烦而且特别浪费空间,因此经过分析我们可以知道是按以下方式来储存的。
先来看一段代码:
#include<string.h>
#include<iostream>
#include<Windows.h>
using namespace std;
class student
{
public:
void display(const char* _name,int _age,const char* _sex);
void print();
private:
char sex[20];
int age;
char name[20];
};
//类外定义成员函数,必须是类名加作用域限定符::(多采用这种定义方式,减少类体的长度)
void student::display(const char* _name, int _age,const char* _sex)
{
strcpy_s(name, _name);
strcpy_s(sex, _sex);
age = _age;
}
void student::print()
{
cout << name << endl;
cout << sex << endl;
cout << age << endl;
}
int main()
{
student t1,t2,t3;
//函数调用相同
t1.display("露露", 19, "女");
t2.display("张三",18,"男");
t3.display("李四",17,"男");
t1.print();
t2.print();
t3.print();
system("pause");
return 0;
}
我们可以从上边的代码看出,创建了三个对象t1,t2,t3但是他们所调用的函数都是相同的,这就需要用以下的储存方法来更加有效的来实现函数调用。
能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。如下图所示。
显然,这样做会大大节约存储空间。C++编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间。
那么问题来了在不同对象但是调用的的代码又相同的情况下,编译器是如何分辨且准确的调用到各自的函数???
在c++中专门设立了一个this指针,用来指向不同的对象,当调用对象t1的成员函数display1时,this指针就指向display1,当调用t2的成员函数display2,this指针就指向display2。。。。。以此类推来分辨准确的调用
this指针在后边会分享给大家
二.类大小的计算
class Bob
{
public:
void MyClass();
private:
int a = 0;
};
int main()
{
cout << sizeof(Bob) << endl;
system("pause");
return 0;
}
class Bob1
{
public:
void Class();
void A();
private:
};
int main()
{
cout << "Bob1->size->"<< sizeof(Bob1) << endl;
system("pause");
return 0;
}
class Bob2
{
public:
private:
};
int main()
{
cout <<"Bob2->size->" <<sizeof(Bob2) << endl;
system("pause");
return 0;
}
class Bob3
{
public:
private:
char b;
int a = 0;
void bob();
};
int main()
{
cout <<"Bob3->size->"<< sizeof(Bob3) << endl;
system("pause");
return 0;
}
从上边四个例子我们可以将类的计算大小总结出以下几点:
-
空类的大小为1(用于区分对象)
-
类的大小,实际就是该类中“成员变量”之和。(都要遵从内存对齐)
-
不论成员函数在类内定义还是类外定义,成员函数的代码段的存储方式是相同的,都不占用对象的存储空间。
-
不论是否用inline声明,成员函数的代码段都不占用对象的存储空间。(inline函数只影响程序的执行效率而与成员函数是否占用对象的存储空间无关)
-
第一个成员在与结构体变量偏移量为0的地址处
-
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数=编译器默认的一个对齐数与该成员大小的比较后的较小值。(vs中默认的值为8,gcc中默认的值为4)
-
结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍
-
如果嵌套了结构体的情况下,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
内存对齐请详看:https://blog.csdn.net/alidada_blog/article/details/81264435