第五节 · 叠加态 · 自定义数据结构

我们所熟知的一切事物都或多或少的由一些特征,这其中有不少特征是可以量化的:

  • 随便找些方的东西,我们可以测量出它的长、宽、高

  • 我们在地球上所处的位置,可以用经纬度与海拔表示

  • 商店所出售的一切物品,都至少有一个进口价(成本价)与售价。

这样的例子实在是太多了。

由此,C++ 拥有一系列的特性,使得我们可以将松散的数据组合起来,成为新的个体,进而便于我们使用。

下面,我们就来探究有关组合自定义数据类型的方式与思想。


最简单的自定义数据类型的方式,莫过于给我们已经掌握的类型取个额外的名字:

typedef long number;		// 给 long 类型取个别名,叫 number

在这里,我们为 long 类型取了一个别名叫 number。现在,我们便可以将 number 作为一个类型使用了,本质上它仍然是 long 类型:

number num1 = 1;			// 定义一个类型为 number 的变量
long num2 = 2;				// long 类型仍然可以正常使用
number num3 = num2;			// 即使名字不同,但它们本质上类型是一致的

typedef 的使用格式如下:

typedef <原类型> <新类型名称>;

原来的类型可以带有类型限定,例如 unsigned

typedef unsigned long long big_num;

而且原类型也可以不是 C++ 自带的类型:

如果要额外带上 const* 这类标识,typedef 是不能应付的。这时我们可以使用 using

using 的声明顺序与 typedef 相反,且中间有等于号隔开:


另一种自定义数据类型的方式是组合。通过组合,我们可以将多个零碎的类型整合为一个新的类型:

我们在这里定义了一个新的名为 block 的类型,可以存储一个三维坐标,其中分别定义了类型为 int成员变量 xyz,以表达长、宽、高。

struct 用于定义一个,它可以容纳一系列变量作为其成员。其格式如下:

struct 定义的类型称作类类型,或也可以简称为。由这个类类型定义的变量,也可以被称作是这个类的一个实例。在花括号内,我们可以如同刚刚的例子那样,声明一系列的成员,例如声明新的成员变量。在花括号之后,我们可以就以这个类型声明一些变量,也可以不声明。但不论怎样,末尾必须以一个分号结束

如果需要在建立类的同时就准备一些这个类的实例,可以在花括号与分号之间写一系列变量名,用逗号隔开:

而且我们同样可以对这些新变量进行初始化:

这种初始化方式称作列表初始化,它可以对形同列表的对象赋予一系列值,其花括号中的每个值按顺序与列表中的每个位置一一对应。在后续有关数组与标准库容器的学习中,我们将更深入地了解它地工作原理。


我们不一定非得在定义类的地方声明这个类类型的变量。事实上,只要声明过这个类,我们就可以在声明的位置之后任意使用这个类创建新变量:

如果将 block 那部分移动到 main 函数的后面,编译器会因为找不到类类型的声明而报错——编译器很笨,它在前半部分解析完之前,不会去撇一眼的后半部分:

如果硬要写在后头怎么办?很简单,在用的地方之前声明一次这个类即可:

顺便一提,像前一个将 struct 写在开头的例子那样,即刚出现就对其进行定义的行为,相当于在声明的同时立即定义这个类。


前期工作已经做好,接下来我们就来尝试使用它们:

要访问类的实例中的内容,需要在该变量后紧跟一个句点(.),再在其后紧跟要访问的成员名。目前来讲,我们所定义的类中暂时只有成员变量 xyz,它们本质上与普通变量没有多大差别。


类型别名与自定义类是可以混用的。举例来讲,我们可以定义两个类 positionsize,分别标识位置与大小:

很显然,它们都有相同的三个成员变量 xyz。既然这样,我们可以试着定义一个通用的含 xyz 的类,然后给它取两个别名,达到同样的效果:

自定义类不仅能取别名,也能嵌套。例如,我们可以将刚刚的两个类 positionsize 再组合,建立一个新类 entity——它是一个具有大小和位置信息的物体类:

对于这种嵌套了别的类的类,使用列表初始化时数据也会是嵌套的,且顺序要保证按照定义类时使用的顺序:

由此可见,类中的类也可以被访问,方式同样是句点加成员名。不论嵌套多深的类,都可以间接地以这种方式访问。


类型别名与自定义类是很有效的数据组织手段,而本节仅仅起到敲门砖的作用。随着学习的深入,我们将在未来的实践中更加深入地熟悉与掌握它们。

Last updated