目录
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。
现在举例一个必须使用初始化列表的场景:
如果一个类中有一个自定义类型的成员,我们在构造函数中也想初始化该成员,在不使用友元和不改变访问限定符的情况下,那构造函数应该要这样写:
那我们只能先创建一个对象,然后进行赋值,这样的方式低效,而且会有以下这种问题。
当 Time 类不提供构造函数时(即构造函数无缺省值),这种方式就行不通了。
所以我们只能使用初始化列表进行初始化,这就是一个必须使用初始化列表的地方。
同样,如果自定义类型存在构造函数,也可以使用初始化列表,这里就不演示了。
我们知道,只能在定义的时候初始化,后面则不能进行修改了,这种情况下也必须使用初始化列表,要不然无法初始化。
除了 const ,我们知道还有引用变量在定义的时候就要初始化要,所以,这种情况也要使用初始化列表,我们来看看是怎么初始化的吧。
上面就出现了一个问题,_y 的改变并没有影响到 x 。
解决方法:传引用即可。
通过以上的了解,总结如下:
结论:
- 自定义类型成员,推荐使用初始化列表初始化。
- 初始化列表可以认为是成员变量定义的地方。
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表初始化,对于自定义类型成员变量,一定会先使用初始化列表初始化。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
第二点结论我们可以推出C++11中打的那个补丁,在成员声明的地方给缺省值的作用。
这个缺省值其实就是给的初始化列表。大家可以看下面这个变化过程,如果函数体内没有 _year=year 这条语句,其实声明时的缺省值默认给了初始化列表。
第三点结论中,虽说推荐使用初始化列表,但是有一些场景使用函数体内初始化也是很不错的,比如在 malloc 开辟空间时:
关于第四点结论,我们来看一道题目就懂了。 初始化按声明顺序初始化。
我们先来看以下两种创建方式,
其中第一个 是直接将2022传参条用构造函数,
另外一个是根据int 类型的2022构造一个 Date 类型的临时变量,然后将该临时变量拷贝给 d2 ,只不过这个过程被编译器所优化,变成了直接调用构造函数。
这本质是一个隐式类型的转化,就像就 int 型数据赋值给 double 型数据类似。
而 explicit 关键字的作用就是阻止这种隐式类型的转化。那我们来看看加上explicit 关键字后的效果。
2.1 概念
声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称之为静态成员变量;
用 static 修饰的成员函数,称之为静态成员函数。
静态成员变量一定要在类外面进行初始化。
静态成员变量声明和初始化举例:
静态成员函数:
2.2 特性
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
- 静态成员变量必须在类外定义,定义时不添加 static 关键字,类中只是声明。
- 类静态成员即可用 类名:: 静态成员 或 对象.静态成员来访问。
- 静态成员函数没有 this 指针,不能访问任何非静态成员。
- 静态成员也是类的成员,受 public、protected、private 访问限定符的限制。
特性一:所有类对象共享
特性三:有两种访问方式,(注意:静态成员同样受访问限定符限制)
特性四:
特性五:
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类。
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在想要进行友元的类中进行内部声明,声明时需要加 friend 关键字。
使用场景:
我们想写一个打印 Date 类中成员的 流操作符重载的全局函数,如下:
此时,这个全局函数是无法访问到类中的私有成员的,所以我们加上 friend,声明这个全局函数是 Date 类的友元。
这样就可以直接访问类中的成员了,注意一定要是全局函数噢。
友元函数说明:
- 友元函数可访问类的私有和保护成员,但不是类的成员函数。
- 友元函数不能用 const 修饰。
- 友元函数可以在类定义的任何地方声明,不受访问限定符的限制。
- 友元函数的调用和普通函数调用原理相同。
- 一个函数可以是多个类的友元函数。
如果是想让一个类中的函数可以友元的访问另一个类中的成员,就要使用下面的友元类了,我们往下看。
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非共有成员。
- 友元关系是单向的,不具有交换性。
比如上述的 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类的私有成员变量,但想在 Time 类中访问 Date 类中私有的成员变量则不行。
- 友元关系不能传递
如果 C 是 B 的友元,B 是 A 的友元,则不能说明 C 是 A 的友元。
使用场景:
我们上面写的 Date 类和 Time 类,我们想在 Date 类中打印出 Time 类的成员,我们就可以使用友元类。
直接在 Date 中调用 Time类中的成员,很明显是不允许的,这时我们就可以使用友元类。
使用友元后:
概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,他不属于外部类,共呢个不能通过外部类的对象取访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:
- 内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
- 内部类在外部类的 public、protected、pribate 定义都是可以的,但是受访问限定符限制。
- 注意内部类可以直接访问外部类中的 static 成员,不需要外部类的对象/类名。
- sizeof(外部类)=外部类,和内部类没有任何关系。
特性1 与 特性 3:
因为 B 天生就是 A 的友元,所以 B 可以访问到 A 中的成员,我们以此举一个打印的例子:
特性4:
sizeof (外部类) 就是外部类的大小,与内部类无关,两个类的大小是没有关联的。