第七章 类
7.1 定义抽象数据类型
1、抽象数据类型
只能访问函数,不能访问成员变量的类称为抽象数据类型
2、*this
当返回值为*this时,返回的是调用该方法实例的引用类型(左值)。
3、IO类型的参数不能被拷贝
IO类型作为函数参数时,只能使用引用而不能使用拷贝。
4、默认构造函数
只有当类没有声明任何构造函数时,编译器才会生成默认的构造函数
5、构造函数初始值列表
在构造函数中,函数参数后使用冒号以及成员变量名加括号初始值的形式为类的成员变量赋初始值
因为构造函数的目的就是初始化成员变量,所以未在构造函数中初始化的成员变量将会默认的使用构造函数初始值列表进行默认初始化。
7.2 访问控制与封装
1、struct和class的区别
struct的默认访问权限是public,class的默认访问权限是private
2、友元函数的声明
当某些类外函数需要访问类实例中私有的成员变量来完成函数操作时,需要将这些函数声明为友元函数。
友元函数的声明是访问权限的声明,函数真正的声明还需要在外面进行。
声明友元函数需要在类内进行,在类的声明前面加上friend关键字
建议将友元函数的声明放在类定义的结束位置。这样可以将友元函数和类放在一起。
7.3 类的其它性质
1、定义在类内部的成员函数是自动内联的
因为一般将函数定义写在类内部的,函数本身都简单,适合展开为内联函数。所以默认将类内部定义的成员函数打上内联的标签。
也可以在类外部声明时打上内联标签,说明该类的成员函数为内联函数。
将简单的函数声明为内联函数,都是为了提高效率
2、类的类型
根据编译原理的知识,c++采用的应该是名字等价。就算类里面的成员是一样的,类的名字不一样,它们的类型也就不一样
3、友元类的声明
同样的,当一个类需要访问另一个类的私有成员变量的时候,可以在被访问的类内部将访问类设置为友元类。
同样的,也可以将另一个类的成员函数设置为友元,这样该类只有声明为友元的成员函数可以访问该类的私有成员变量。
4、重载函数与友元
对于重载函数,存在多个版本。
在类中需要对每个版本都要进行友元声明
7.4 类的作用域
1、每个类相当于一个命名空间
此处ScreenIndex是在类内用typedef定义的一个新的类型,并且这个类型只在类内空间有效。
2、外层作用域的查找
如果全局变量和类内的成员变量重名,使用 :: 作用域运算符指明所需变量为类外的全局变量(不推荐重名)
7.5 构造函数再谈
1、区分“先定义后赋值”以及“定义并初始化”
对于类的构造函数来说,在初始值列表中进行的是**“定义并初始化”**
而在构造函数内部使用等号赋值来说,是**“先定义后赋值”**
对于某些const常量或者没有默认构造函数的类来说。
如果使用的是“初始化”,哪没问题。
但如果使用的是“复制赋值”,哪就出问题了!
所以构造函数的初始值列表有时候必不可少!
2、成员初始化顺序
在某些情况下,一个成员的初始化需要用到另一个成员的值,此时成员初始化的顺序就至关重要了。
一般来说,构造函数初始值列表的初始化的顺序是按照类中成员出现的先后顺序来执行的。而不是按初始值列表中出现的顺序来决定的:
此时,应该是先初始化i,后初始化j。但是如果先初始化i就会用到未初始化的j,所以就会报错。
如果可能,尽量避免使用一个成员初始化另一个成员的情况。应该尽量使用构造函数的参数进行初始化。
3、委托构造函数
在构造函数的初始值列表中调用其它构造函数,这样就称之为委托构造函数。委托别的构造函数帮我进行初始化操作
执行顺序:委托方的初始值列表、被委托方的初始值列表、被委托方的代码块、委托方的代码块
4、使用默认构造函数
5、类的隐式转换
当类的构造函数只接受一个参数时,可以将该参数类型隐式地转换为类类型
B只接受1个参数,并且该参数的类型为string类型
ShowB函数接收一个B类型的变量,并且将该变量的成员变量s打印出来
在调用ShowB函数时,可以通过传入一个字符串类型的变量实现将“字符串类型”隐式转换为“B类型”。
①、这种转换只能允许一步类型转换
上图第一个函数调用执行了两步转换:
char* -> string
string -> Sales_date
所以该调用是错误的
②、可以通过在类内相应构造函数前声明explicit禁止该转换
③、声明为explicit的构造函数无法使用拷贝初始化
6、聚合类
直接访问其成员
7.6 类的静态成员
1、声明静态成员
- 在成员的声明之前加上关键字static使得其与类关联在一起。
- 静态成员可以是public的或private的。
- 类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据
- 静态成员函数不与任何对象绑定在一起,它们不包含this指针。
2、使用类的静态成员变量
①、使用作用域运算符直接访问
②、通过实例直接访问
③、类内函数直接访问
3、在类外定义静态成员
一般来说,类的静态成员应该在类外进行初始化。并且它们的生命周期存在于整个程序的生命周期之中。
4、在类外初始化静态成员
通常情况下,类的静态成员变量不应该在类的内部初始化。但是一些字面量可以在类内初始化。
此时还需要再类外加上声明,但是不附上初始值