7.1 定义抽象类型
-
this指针
调用成员函数时,实际上在替某个对象调用它,成员函数通过一个名为
this
的额外的隐式参数来访问调用它的那个对象//实际执行过程 Sales_data::isbn(&total); //在total对象调用函数时,将对象的地址传入,初始化this指针 //任何对类成员的直接访问都可以被看做this的隐式引用 return book; //等价于 return this->book; book为数据成员
-
引入
const
成员函数string isbn() const {return bookNo};
- this的类型是ClassType *const顶层const,不能让其指向const ClassType对象也就使得,不能在常量对象上调用普通的成员函数
- 通过使用const修改this指针的类型为
const ClassType *const
,这样的函数成为常量成员函数 - 常量对象,以及常量对象的引用和指针,只能调用常量成员函数
-
构造函数
- 构造函数不能声明为const,构造函数的结果就是隐式的返回一个对象,如果这个对象是const的,那它就不能访问非const的函数。
- 构造函数在const对象的构造过程中可以向其写值。
- 对于数据成员,若存在类内初始值,则使用其进行初始化,否则执行默认初始化
-
一个普通的类必须定义自己的默认构造函数
- 只有在未定义任何构造函数的情况下才会自动生成默认构造函数,一旦定义了自己的构造函数,则必须有默认构造函数
- 合成的构造函数可能执行错误的操作(定义在块内的内置类型和复合类型的对象被默认初始化,其值将是未定义的)
- 不能为某些类合成构造函数,类中包含其他类类型,并且该类型没有默认构造函数
- 使用=default,在类内,使得默认构造函数是内联的
-
初始值列表
Sales_data(const string& s):bookNo(s){} //冒号后面即为初始值列表 //不同成员之间使用逗号分隔 //不在列表中的成员执行默认初始化
没有在构造函数初始值列表中显示初始化成员,则该成员将在构造函数体之前执行默认初始化,然后再执行函数体的赋值操作
7.2 访问控制与封装
-
友元
-
令其他类或者函数成为它的友元
-
friend关键字开始的函数声明
-
定义在类内部,友元函数必须指明其属于哪个类
class A { public: friend class C; private: int data; } class C { public: void show(A a) { cout<<a.data<<endl; } }
-
友元仅指定了访问权限,而非真正的声明
-
若希望能调用某个友元函数,那么必须在友元声明外再对函数声明一次
-
友元不具备传递性
-
-
定义在类内部的成员函数是自动inline的
-
mutable
可变数据成员,被mutable修饰的成员永远不会是const,即使是const对象的成员,也可以修改
-
不完整类型
可以定义指向该类型的指针或引用,也可以声明(但不能定义)以其为参数或者返回类型的函数,一个类的成员类型不能是该类自己
7.3 构造函数再探
-
初始化顺序
-
成员的初始化顺序与定义顺序一直,不受初始值列表顺序的影响。
-
如果一个构造函数为所有参数都提供了默认实参,那么实际上也就定义了默认构造函数
-
-
委托构造函数
//使用所在类的其它构造函数执行自己的初始化过程 //即把自己的一些职责委托给其他构造函数 class Sales_data { public: Sales_data(string s,unsigned cnt,double price): bookNo(s),units_sold(cnt),revenue(cnt*price){} Sales_data():Sales_data("",0,0){} //委托构造函数 Sales_data(string s):Sales_data(s,0,0){} //委托构造函数 }
-
隐式的类类型转换(转换构造函数)
在
Sales_data
类中,接受string的构造函数和接收istream的构造函数分别定义了这种类型向Sales_data
隐式转换的规则,即可用string 和istream作为Sales_data的替代string null_book="999"; item.combine(null_book); //item是类的对象,combine定义的形参也是类类型,这里直接使用string 代替 //即可以隐式转换 //但是这种隐式转换编译器只能执行一不 item.combine("999"); //错误
-
抑制构造函数定义的隐式转换
//使用explicit关键字 explicit Sales_data(const string &s):bookNo(s){}
-
聚合类
-
所有成员都是public
-
没有定义任何构造函数
-
没有基类,没有虚函数
-
可以使用一个花括号括起来的成员初始值列表,来初始化聚合类数据成员
class A { public: string s; int i; } ... A a={"xxx",0}; //若列表的大小小于数据成员,靠后的将被【值初始化】 //其长度不能大于数据成员长度
-
-
值初始化
当对象被默认初始化或者值初始化时,自动执行默认构造函数
- 数据初始化过程中,提供的初始值少于其大小时,执行值初始化
- 不使用初始值定义一个局部静态变量时
- 通过T()的形式显示地请求初始化时
7.4 类的静态成员
- 静态成员与类的本身相关,而不是与类的对象保持关联
- 类的静态成员存在于任何对象之外
- 静态成员函数不与任何对象绑定,其不含this指针,同时静态成员函数不能声明为const
- 虽然静态成员不属于类的对象,但是可以用类的对象、指针、引用来访问,成员函数可以不使用作用域运算符就可以直接访问静态成员
- 静态数据成员不由构造函数初始化,并且一般不能再类的内部初始化静态数据成员,应该定义在任何函数之外
- 静态数据成员可以是不完整类型,特别的,可以是所属的类类型
- 可以使用静态成员作默认参数