## 第7章 类
### 7.1.2
- 定义在类内部的函数都是隐式的inline函数。
- 在成员函数的声明中,紧跟在参数列表之后的**const**表示**this**是一个指向常量的指针。这样的成员函数被称作常量成员函数。常量对象,以及常量对象的引用或指针都只能调用常量成员函数。
- 编译器分两步处理类:首先编译成员的声明,然后编译成员函数体。
- 返回this对象:
```cpp
return *this; //返回调用该函数的对象
```
### 7.1.3
一般来说,如果非成员函数是类接口的组成部分,则这些函数的声明应该与类在同一个头文件内。
### 7.1.4
- 构造函数不能被声明成const的。
- 只有当类没有声明任何构造函数时,编译器才会自动地生成默认构造函数,此时必须定义一个默认构造函数。
- 如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,那么编译器将无法初始化该成员,即无法合成默认的构造函数。
- 在C++11新标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上`= default`来要求编译器生成构造函数。
### 7.1.5
需要动态内存的类应尽量使用vector对象或者string对象管理必要的存储空间,这样能避免分配和释放内存带来的复杂性。
### 7.2 访问控制与封装
使用**class**定义类时,默认访问权限是**private**;使用**struct**定义类时,默认访问权限是**public**。
### 7.2.1
- 友元不是类的成员,也不受它所在区域访问控制级别的约束。
- 友元声明并非通常意义上的函数声明。通常建议在友元声明之外再专门对函数进行一次声明。
### 7.3.1
- 类中用来定义类型的成员必须先定义后使用。
- inline成员函数应与相应的类**定义**在同一个头文件中。
- **mutable**声明无视const
一个可变数据成员(mutable data member)永远不会是const,即使它是const对象的成员。因此,一个const成员函数可以改变一个可变成员的值。
### 7.3.3
不完全类型(incomplete type)的类只能在以下有限情景中使用:
- 可以定义指向这种类型的指针或引用
- 可以声明(但是不能定义)以其作为参数或者返回类型的函数
### 7.3.4
友元关系不存在传递性。
### 7.4.1
编译器处理完类中的全部声明后才会处理成员函数的定义。
### 7.5.1
- 类成员的初始化顺序与它们在类定义中的出现顺序一致。构造函数初始化列表中初始值的前后位置关系不会影响实际的初始化顺序。
- 如果一个构造函数为所有参数都提供了默认实参,则它实际上也定义了默认构造函数。
### 7.5.2 委托构造函数(delegating constructor, C++11)
当一个构造函数委托给另一个构造函数时,受委托的构造函数的初始值列表和函数体被依次执行。然后控制权交还委托者的函数体。
### 7.5.4
- 如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称作**转换构造函数**。
- 通过在类内声明处添加**explicit**声明可以抑制构造函数定义的隐式转换,不允许在类外声明或定义时出现。使用explicit声明的构造函数只能以直接初始化的形式使用,而不能以拷贝初始化的形式使用。
- 练习7.4,7.5,7.9,7.15,7.22,7.50
```cpp
/* 文件名:Person.h */
/* C++ Primer中文版第5版, 第7章系列练习 */
/* 主要内容: 类的基础知识 */
/* 日期:2017-09-18 */
#ifndef _PERSON_H_
#define _PERSON_H_
#include <iostream>
#include <string>
class Person{
friend std::istream &readPerson(std::istream &is, Person &person);
friend std::ostream &printPerson(std::ostream &os, Person &person);
public:
Person() = default;
Person(const std::string &name_, const std::string &addr_) : name(name_), addr(addr_) {}
explicit Person(std::istream &is) { readPerson(is, *this); }
std::string name() const { return this->name; }
std::string addr() const { return this->addr; }
private:
std::string name;
std::string addr;
};
std::istream &readPerson(std::istream &is, Person &person)
{
is >> person.name >> person.addr;
return is;
}
std::ostream &printPerson(std::ostream &os, Person &person)
{
os << person.name << " " << person.addr;
return os;
}
#endif
```
### 7.6 类的静态成员
- 静态成员函数不能声明成const的,也不能在函数体内(无论是显式地或者隐式地)使用this指针。但成员函数不用通过作用域运算符就能直接使用静态成员。
- 静态成员函数只能在类内部使用static声明,不能在类外部定义时重复该关键字。
- 通常情况下应该在类的外部定义和初始化每个静态成员。如果在类的内部提供了一个初始值,则类外对成员的定义不能再指定初始值。
- 静态数据成员可以是**不完全类型**,静态数据成员的类型可以是它所属的类类型。静态成员可以作为默认实参。