C++ Primer Chapter 7 Classes
用于创建无线网
netsh wlan set hostednetwork mode=allow ssid=NetName key=password
2024/05/30
类的基本思想是数据抽象 (data abstraction)和封装(encapsulation)。数据抽象是一种依赖于 接口(interface) 和 实现(implementation) 分离的编程(以及设计)技术。
类的接口包括用户所能执行的操作;类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
封装实现了类的接口和实现的分离。封装后的类隐藏了它的实现细节,也就是说,类的用户只能使用接口而无法访问实现的细节。
7.1 定义抽象数据类型
7.1.1 设计Sales_data类
成员函数(member function)
使用改进的Sales_data类
在这里插入代码片
7.1.2 定义改进的Sales_data类
Note 定义在类内部的函数是隐式的inline函数。
定义成员函数
引入this
成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。
例如,如果调用
total.isbn();
则编译器负责把total的地址传递给isbn的隐式形参this,可以等价地认为编译器将该调用重写成了以下的形式:
//伪代码,用于说明调用成员函数的实际执行过程
Sales_data::isbn(&total)
任何自定义名为this的参数或变量的行为都是非法的。我们可以在成员函数体内部使用this。
因为this的目的总是指向“这个”对象,所以this是一个常量指针,我们不允许改变this中保存的地址。
引入const成员函数
相当抽象,没有理解来
类作用域和成员函数
编译器分两步处理类:
首先编译成员的声明,然后才轮到成员函数体(如果有的话)。
因此,成员函数体可以随意使用类中的其他成员而无需在意这些成员出现的次序。
在类的外部定义成员函数
7.1.3 定义类相关的非成员函数
Note 一般来说,如果非成员函数是类接口的组成部分,则这些函数的声明应该与类在同一个头文件内。
7.1.4 构造函数(constructor)
constructor
不同于其他成员函数,构造函数不能被声明成const的。
当我们创建一个const对象时,直到构造函数完成初始化过程,对象才真正取得其“常量”属性。因此,构造函数在const对象的构造过程中可以向其写值。
合成的默认构造函数
如果我们的类没有显式定义构造函数,那么编译器就会为我们隐式地定义一个默认构造函数。
编译器创建的构造函数又被称为合成的默认构造函数(synthesized defaule constructor)。
对于大多数类来说,这个合成的默认构造函数将按照如下规则初始化类的数据成员:
●如果存在类内的初始值,用它来初始化成员。
●否则,默认初始化该成员。
某些类不能依赖于合成的默认构造函数
Note 只有当类没有声明任何构造函数时,编译器才会自动地生成默认构造函数。
WARNING 如果类包含有内置类型或复合类型的成员,则只有当这些成员全都被赋予了类内的初始值时,这个类才适用于合成的默认构造函数。
有的时候编译器不能为某些类合成默认的构造函数。
例如,如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,那么编译器将无法初始化该成员。
对于这样的类来说,我们必须自定义默认构造函数,否则该类将没有可用的默认构造函数。
定义Sales_data的构造函数
Best Practices 构造函数不应轻易覆盖掉类内的初始值,除非新赋的值与原值不同。如果你不能使用类内初始值,则所有构造函数都应该显示地初始化每个内置类型的成员。
注解:类内的初始值,应该是指声明时给变量赋的初始值
在类的外部定义构造函数
7.2.1 友元
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或函数成为它的友元(friend)。
如果类想把一个函数作为 它的友元,只需要增加一套以friend关键字开始的声明语句即可:
friend Sales_data add(const Sales_data&, const Sales_data&);friend std::istream& read(std::istream&, Sales_data&);friend std::ostream& print(std::ostream&, const Sales_data&);
友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。友元不是类的成员也不受它所在区域访问控制级别的约束。
Tip 一般来说,最好在类定义开始或结束前的位置集中声明友元。
关键概念:封装的益处
封装有两个重要的优点:
● 确保用户代码不会无意破坏封装对象的状态。
● 被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
Note 尽管当类的定义发生改变时无须改变用户代码,但是使用了该类的源文件必须重新编译。
友元的声明
友元的声明仅仅指定了访问的权限,而非一个通常意义上的函数声明。如果我们希望类的用户能够调用某个友元函数,那么我们就必须在友元声明致亲爱再专门对函数进行一次声明。
注解:friend只是一个访问权限修饰符