第七章:类
一、定义抽象数据类型
1、成员函数的声明必须在类的内部,定义可以内部也可以外部;作为接口组成部分的非成员函数,定义和声明都在外部
- 如果类函数定义在类内部,则隐式为inline函数
- 在声明时声明inline,然后在类外定义函数,可以可以构造inline函数
- inline成员函数应该和类的定义在同一个头文件中
2、this:成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象
Sales_data total; //实例化total对象 total.isbn(); = Sales_data::isbn(&total)
//调用类函数时,编译器把total的地址传递给isbn隐式形参this std::sting isbn() const {return bookNo} //成员函数内部不需要this可以直接调用 = std::sting isbn() const {return this->bookNo} //上面的其实是这样调用的
- 任何类成员的直接访问都被看成是this的隐式引用
- this是一个常量指针:Sales_data *const:不允许修改隐式this中的地址
Sales_data& Sales_data::combing(const Sales_data &rhs) { ... return *this; //解引用this指针获得执行该函数的对象,即返回totoal的引用 }
- 返回引用的函数是左值,可以连用:myScreen.move(4,0).set(‘#’);
- 如果返回不是引用,则连用是通过拷贝副本实现,则上面变成了myScreen.move(4,0);myScreen.set(‘#’);两条语句
3、const成员函数:
std::sting isbn() const {return bookNo} //const可以修改this的类型为常量类型 从Sales_data * const 变成 const Sales_data* const类型
- 这样可以在常量对象上使用成员函数:常量对象,常量对象的引用或指针只能调用常量函数
- 常量成员函数不能改变它调用对象的内容
- 可以在成员数据前加mutable关键字,做到定义为可变类型,这样就算是在const成员函数依旧可以改变该数据
- const Screen &dispaly(A) const {return *this}:一个const成员函数如果以引用的形式返回*this,返回类型也得是常量引用
4、定义类相关的非成员函数
- 这些函数的声明应该与类放在同一个头文件中
- IO类属于不能拷贝的类型,只能通过引用来传递
- 执行输出任务的函数应该尽量减少对格式的控制,来确保由用户来决定是否换行
- 默认情况下,拷贝类的对象其实拷贝的是对象的数据成员
5、构造函数
- 构造函数的名字与类名相同
- 构造函数不能声明成const
- 对于一个普通类必须定义自己的默认构造函数
- 通过在参数列表后面写上= default来要求编译器生成默认构造函数
- 通常情况下,构造函数使用类内初始值不失为好的选择
- 后遭函数不应该轻易覆盖掉类内的初始值
- 如果成员是const或者引用,必须将其初始化(给默认值或使用构造函数)
- 最好令构造函数初始值的顺序与成员声明的顺序保持一致
- 尽量避免使用某些成员初始化其他成员
- 当一个构造函数委托另一个构造函数时,受委托的构造函数的初始值和函数体依次执行
- 假如受委托的构造函数体包含有代码的话,先执行这些代码,然后控制权才会交还给委托者的函数体
- 如果构造函数只接受一个实参,则定义了类类型的隐式转换机制
- 编译器只会自动执行一步类型转换
- 关键字explicit支队一个实参的构造函数有效,可以抑制构造函数定义的隐式转换:即只能直接初始化
- explicit只能出现在类内声明构造函数时,在类外部定义时不应重复
二、访问控制与封装
1、构造函数和部分成员函数紧跟在public说明符后;数据成员和作为实现部分的函数紧跟在private后面
2、使用class和struct定义的唯一区别是默认的访问权限不同
3、友元:在声明开头加一个friend,允许该声明的类或函数访问类的非公有成员
- 友元不是类的成员,也不受区域访问控制级别的约束
- 最好在类定义开始或结束前的位置集中声明友元
- 友元的声明仅仅指明了访问的权限,而非一个普通意义上的函数声明
- 如果类的用户要使用某个友元函数,必须在友元声明之外再专门对函数进行一次声明
- 如果一个类指定了友元类,则友元类的成员函数可以访问此类包含非公有成员在内的所有成员
- 每个类负责控制自己的友元类或友元函数,不存在传递性
- 对于重载函数声明成友元,不许每个都分别声明
- 就算在类的内部定义该函数,也必须在类的外部提供相应的声明从而使得函数可见
- 通常把友元的声明与类本身放在同一个头文件中
三、类的其他特性
1、类型成员:在类内定义自己的类型,类型名通常出现在类开始的地方
2、提供一个类内初始值时,普通数据使用=初始化;其他如类数据使用花括号初始化
四、类的作用域
1、一个类就是一个作用域,类的外部,成员的名字被隐藏起来了
2、成员函数定义在类外部时:
- 一旦遇到了类名,定义的剩余部分就在类的作用域内了,包括参数列表和函数体
- 因为函数的返回类型出现在函数名之前,所以返回类型必须指明是哪个类的成员
五、类的静态成员
1、静态成员函数不予任何对象绑定在一起,不包含this指针,也不能声明成const
2、可以直接使用作用域预算符访问静态成员,而无需构建对象
3、既可以在类内部也可以在类外部定义静态成员函数,
- 当在类外部定义静态成员是,不能重复static关键字,该关键字只出现在类内部
- 不能在类的内部初始化静态成员,必须在类的外部定义和初始化每个静态成员
- 一个静态数据成员只能定义一次
- 一旦被定义,就一直存在程序的整个生命周期中
- 最好把静态数据成员定义在.cpp文件中
4、静态成员可用的特殊场景
- 静态数据成员可以使不完全类型
- 静态数据成员可以就是它所属的类类型
- 可以用静态成员作为默认实参