结构体内存对齐:总向它的最大元素对齐,如果结构体嵌套,内部结构体被看作一个整体。
代码规范:结构体声明时候,按照变量大小,从小到大书写,避免浪费空间。
c 语言中的 struct 只是变量的打包, c++中的 struct 是一个域。
低位存低位是小端,低位存高位是大端
一、结构体在C和C++的不同
- 在c++中,用结构体定义变量不需要加struct,而C中不行;
- 在c++中,可以定义空结构体,大小为1,而C中不行;
- 在c++中,可以在结构体中声明甚至实现函数,在c中只能放变量或者函数指针;
- 在c++中,成员函数直接可以访问本结构的成员变量无需传入,在c中,函数和结构并无直接关联。
成员函数不影响结构体的大小:
因为成员函数是放在公共区域的,只是在这个结构体域中。
内存对齐方法:向最大值对齐。
为什么要内存对齐:空间换时间,提高效率;(跳转的次数变少) - 如何知道结构体中某个成员相对于结构体起始位置的偏移量?
把成员和结构体的指针取出来转成char* 类型相减。
二,类
类是一类特殊的结构体。空类也占一个字节的空间。
类中的函数是存在公共区,不在类中。所以每个类只有自己的成员变量,没有自己的成员函数。
写在类内部的成员函数默认 inline (内联)。
访问限定符:public, private, protrected.
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
private不能被继承,protected可以被继承。 - 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
** this指针:**
一般成员函数中都含有一个this指针,这个指针指向调用这个成员函数的对象。
this 指针一般存在栈上,有的编译器会优化到寄存器中。
C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
- this指针的类型:类类型* const;
this指针是当前类类型的指针,this是一个常量指针,指针指向不能改变。 - 只能在“成员函数”的内部使用 ;
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参
传递给 this 形参。所以对象中不存储this指针; - this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,
不需要用户传递。
this指针存在哪里? this指针可以为空吗?
存在成员函数的栈里作为临时变量,是一个参数,用完就丢。
this 可以为空,没有成员变量,但是有成员函数,可以调用不用任何成员变量的成员函数,
不进行解引用操作的时候,this可以为空。
三、六个默认成员函数
构造函数
- 构造函数是一个特殊的成员函数,不存在返回值。名字和类名相同,在实例化对象的时候
自动调用。 - 系统会自动提供一个默认的构造函数,如果自己实现了构造函数,则系统不再提供默认
的构造函数。 - 构造函数可以存在参数,它与其它的构造函数是以函数重载的方式共同存在的。
- 一般会定义一个全缺省构造函数。
默认构造函数:(默认构造函数只能存在一个) - 无参构造:编译器默认生成,(空的函数体)
- 全缺省构造函数。
编译器默认生成的构造函数对于内置类型,不进行任何操作,对于自定义成员,会
完成自定义类型的初始化。
所有的构造函数都会自动调动自定义类型的默认构造。
拷贝构造
关于参数类型:
const &: 可以接收任何类型的类对象,临时对象也可以接收。
若为& : 只能接收非临时类对象,因为临时对象有常性。
传值: 会引起无穷递归。
编译器默认生成的拷贝构造完成按字节拷贝。
浅拷贝? 直接按字节复制内存
深拷贝? 当成员中有指向堆的指针就必须重新给该指针分配空间,然后将目标对象指针
所指空间内容拷贝到新分配的空间。(如果不这样做,会导致两个指针指向同一
片空间,从而析构中多次释放)。
析构函数
析构完成对象资源清理,整个生命周期只调用一次:销毁对象之前调用,本身不销毁对象。
如果有资源,显示定义析构,完成资源清理,否则会有内存泄漏。
每一个类只有一个析构函数,析构函数没有参数。
析构函数会自动调动自定义成员的析构函数。
赋值运算符重载
编译器自动生成的是个浅拷贝复制。参数一般传引用。
const修饰类的成员函数
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰
该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修饰。
void func()const 实际上相当于 void func(const 类名* this)
const 成员函数不能调用其他成员函数,其他成员函数可以调用const 成员函数。
static 成员
- 不属于对象,属于类成员。
- 类的所有对象共享
- 储存在数据段
4.必须在类外初始化。
5.既可以使用(对象 .) 访问,又可以使用(类名::)访问,没有 this 指针。
6.静态成员函数内部不能调用非静态成员函数(因为没有 this 指针),非静态成员函数内
部可以调用静态成员函数。
初始化列表
一般按照声明的顺序来写初始化列表。因为成员变量在类中声明次序就是其在初始化列表
中的初始化顺序,与其在初始化列表中的先后次序无关。 - 狭义初始化:
在定义变量的时候直接进行初始化 - 广义初始化
指的是第一次给变量初始化
初始化列表相当于狭义初始化,而构造函数内部相当于广义初始化。
所以初始化列表可以解决一些只能用狭义初始化进行初始化的变量,例如: - const 变量;
- 引用;
- 没有默认构造函数的类类型成员。
上述三种类型必须在初始化列表中初始化(const 类成员变量在C++11中可以定义时初始化)
友元
友元分为友元函数和友元类。友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于类,但是需要
在类的内部声明,声明时需要加 frind 关键字。- 友元函数可以访问类的私有成员,但是不是类的成员函数;
- 友元不能用const修饰;
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制;
- 一个函数可以是多个类的友元函数;
- 友元函数的调用和普通函数的调用的原理相同。
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有成员。
1. 友元关系是单向的。 例如:A是B 的友元类,A可以访问B的私有成员,反之不行。
2. 友元关系不能传递。如果B是A的友元,C是B的友元,则不能说明C时A的友元。
内部类
如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个
独立的 类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有
任何优越的访问权限。
内部类就是外部类的友元类。内部类可以通过外部类的对象参数来访问外部类中的所有成
员。但是外部类不是内部类的友元
1. 内部类可以定义在外部类的public、protected, private都行; - 内部类可以直接访问外部类的static, 枚举成员, 不需要外部类的对象 / 类名;
- 外部类的大小和内部类无关:sizeof(外部类)=外部类