2.6 自定义数据结构
文章目录
2.6.1 定义类(struct)
我们的类以关键字 struct 开始,紧跟着类名和类体(其中类体部分可以为空)。类体由花括号包围形成了一个新的作用域。类内部定义的名字必须唯一,但可以与类外部定义的名字重复。
类体右侧的表示结束的花括号后必须写一个分号,因为类体后面可以紧跟变量名以示对该类型对象的定义。一以下两种表示方式是等价的:
// 法一
struct Sales_data { /* ... */ } accum, tram, *salesptr;
// 法二(最好使用这种方式,将对象和类的定义分开)
struct Sales_data { /* ... */ };
Sales_data accum, tram, *salesptr;
2.6.2 头文件的编写
为了确保各个文件中类的定义一致,类通常被定义在头文件里,而且类所在头文件的名字应与类的名字一样,例如应该把Sales_data类定义在名为Sales_data.h的头文件中。头文件通常包含那些只能被定义一次的实体,如类、const和constexptr变量等。
【预处理器概述】
确保头文件多次包含仍能安全工作的常用技术是预处理器。预处理器是在编译之前执行的一段程序,可以部分地改变我们所写的程序。例如,预处理功能#include,当预处理器看到#include标记时就会用指定的头文件的内容来替代#include。
【#define、#ifdef、#ifndef、#endif】
C++程序还会用到一项预处理功能是头文件保护符,头文件保护符依赖于预处理变量。预处理变量有两种状态:已定义和未定义。 #define 指令把一个名字设定为预处理变量,另外两个指令分别检查某个指定的预处理变量是否已经定义: #ifdef 当且仅当变量已定义时为真;#ifndef 当且仅当变量未定义时为真,一旦检查结果为真,则执行后续操作直至遇到 #endif 指令为止。
这些功能能够有效防止重复包含的发生:
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data {
std::string bookNo; // ISBN
unsigned units_sold = 0; // 销售数量
double revenue = 0.0; // 销售总收入
};
#endif // SALES_DATA_H
上述例子中,第一次包含Sales_data.h时,#ifndef的检查结果为真,SALES_DATA_H还未定义,因此预处理器将顺序执行执行后面的操作,直至遇到#endif。此时,预处理变量SALE_DATA_H的值变为已定义,而且Sales_data.h也被拷贝到我们的程序中来。后面,如果再一次包含Sales_data.h,则#ifndef的检查结果为假,编译器就会忽略掉#ifndef到#endif之间的部分。
【注意】整个程序的预处理变量包括头文件保护符必须唯一,通常的做法是基于头文件中类的名字来构建保护符的名字,以确保唯一性。为了避免与程序中的其它实体发生名字冲突,一般把预处理变量的名字全部大写。