封装:
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
使用protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访问,所以封装本质是一种管理。
类的作用域:
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域。
class Person { public: void PrintPersonInfo(); private: char _name[20]; char _gender[3]; int _age; }; void Person::PrintPersonInfo() { //Person类中的 cout<<_name<<" "_gender<<" "<<_age<<endl; } int main(){ //结构体一样用 Person a; a._name[0]; a._gender[0]; a._age; }
类的实例化:
类的大小计算方法:
//类对象的大小 //大小是:1 //空类:1字节 class A{ }; //大小是:1 //成员函数:1字节 class B{ public: void fun() { int a = 10; } }; //大小是:16 class C{ public: void fun() { int a = 10; } private: char c; //1 int a; //必须是 4 的倍数开始,前 4 个放char double d; //前面占了 8 个 //8+8=16 //成员变量最大 8 = 默认对齐数 8,取 8 的倍数 =16 }; //大小:24 class D{ public: void fun() { int a = 10; } private: char c; //1 double d; //必须 8 的倍数,前八个放char int a; //前 16 个放了,16 又是 4 的倍数 //8+8+4=20 //成员变量最大 8 = 默认对齐数 8,取 8 的倍数=24 }; //大小是:16 class E{ public: void fun() { int a = 10; } private: double d; //8 char c; //1 int a; //必须 4 的倍数开始,前 8+4(char放四个) 个放了 //8+4+4=16 //成员变量最大 8 = 默认对齐数 8,取 8 的倍数=16 }; //大小是:32 class F{ public: void fun() { int a = 10; } private: double d; //8 char c; //1 int a; //必须 4 的倍数开始,前 8+4(char放四个) 个放了 //8+4+4=16 //成员变量最大 8 = 默认对齐数 8,取 8 的倍数=16 class BB{ public: char c; double d; }; //这时候还是16,因为只是定义,F类还不包含BB //如果创建了一个对象 BB bb,这才成为F包含BB BB bb; //这是大小 = 32 //F类大小16 BB大小 16字节 之和=32 //成员变量最大 8 = 默认对齐数 8,取 8 的倍数=32 }; int main(){ cout << "A:" << sizeof(A) << endl; //结果是:1 cout << "B: " << sizeof(B) << endl; //结果是:1 cout << "C:" << sizeof(C) << endl; //结果是:16 cout << "D:" << sizeof(D) << endl; //结果是:24 cout << "E:" << sizeof(E) << endl; //结果是:16 cout << "F:" << sizeof(F) << endl; //结果是:32 } //涉及内存对齐问题 VS默认对齐 8 字节 //char 一个字节 //int 四个字节 //double 八个字节 //VS默认对齐数是8
- 在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个 int 则占用4字节而不是5字节。
- 如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的处。
注:对齐数= 编译器默认的一个对齐数 与 该成员大小 的比较后的较小值。
类对象的大小:
结论:一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。内存对齐时:每个和默认对齐数比较取最小的,整个类型进行比较。
结构体内存对齐规则:
- 第一个成员在与结构体偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 注意:对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。 VS中默认的对齐数为8,gcc中的对齐数为4。注:自己可以调整但是不建议调整,默认就好。
- 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
问:
1. 结构体怎么对齐? 为什么要进行内存对齐?答:结构体对齐:对齐字节。
答:内存对齐原因:访问内存是一块一块的访问的1(2^0),2(2^1),4(2^2)……,如果不对齐,访问数据的时候需要内存字节拼接,很麻烦,并且硬件要求也需要内存对齐。
2. 如何让结构体按照指定的对齐参数进行对齐?
答:#pargma pack(4):这样就设定默认对齐数是4。
3. 如何知道结构体中某个成员相对于结构体起始位置的偏移量?
答:cout<<&(((C*)0)->a)<<endl; 含义是:C类中 a 对象相对于其实地址的偏移量。(自己会算也可以)
4. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景?
答:大端:高地址存低位,低地址存高位;小端:低地址存低位,高地址存高位。
答:通信当中。
this指针:
C++编译器给每个“成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性:
- this指针的类型:类类型* const。
- 只能在“成员函数”的内部使用。
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
问题:
1. this指针存在哪里?2. this指针可以为空吗?