第五节 · 叠加态 · 自定义数据结构
我们所熟知的一切事物都或多或少的由一些特征,这其中有不少特征是可以量化的:
随便找些方的东西,我们可以测量出它的长、宽、高
我们在地球上所处的位置,可以用经纬度与海拔表示
商店所出售的一切物品,都至少有一个进口价(成本价)与售价。
这样的例子实在是太多了。
由此,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 的成员变量 x、y、z,以表达长、宽、高。
struct 用于定义一个类,它可以容纳一系列变量作为其成员。其格式如下:
由 struct 定义的类型称作类类型,或也可以简称为类。由这个类类型定义的变量,也可以被称作是这个类的一个实例。在花括号内,我们可以如同刚刚的例子那样,声明一系列的成员,例如声明新的成员变量。在花括号之后,我们可以就以这个类型声明一些变量,也可以不声明。但不论怎样,末尾必须以一个分号结束。
如果需要在建立类的同时就准备一些这个类的实例,可以在花括号与分号之间写一系列变量名,用逗号隔开:
而且我们同样可以对这些新变量进行初始化:
这种初始化方式称作列表初始化,它可以对形同列表的对象赋予一系列值,其花括号中的每个值按顺序与列表中的每个位置一一对应。在后续有关数组与标准库容器的学习中,我们将更深入地了解它地工作原理。
我们不一定非得在定义类的地方声明这个类类型的变量。事实上,只要声明过这个类,我们就可以在声明的位置之后任意使用这个类创建新变量:
如果将 block 那部分移动到 main 函数的后面,编译器会因为找不到类类型的声明而报错——编译器很笨,它在前半部分解析完之前,不会去撇一眼的后半部分:
如果硬要写在后头怎么办?很简单,在用的地方之前声明一次这个类即可:
顺便一提,像前一个将 struct 写在开头的例子那样,即刚出现就对其进行定义的行为,相当于在声明的同时立即定义这个类。
前期工作已经做好,接下来我们就来尝试使用它们:
要访问类的实例中的内容,需要在该变量后紧跟一个句点(.),再在其后紧跟要访问的成员名。目前来讲,我们所定义的类中暂时只有成员变量 x、y、z,它们本质上与普通变量没有多大差别。
类型别名与自定义类是可以混用的。举例来讲,我们可以定义两个类 position 与 size,分别标识位置与大小:
很显然,它们都有相同的三个成员变量 x、y、z。既然这样,我们可以试着定义一个通用的含 x、y、z 的类,然后给它取两个别名,达到同样的效果:
自定义类不仅能取别名,也能嵌套。例如,我们可以将刚刚的两个类 position 与 size 再组合,建立一个新类 entity——它是一个具有大小和位置信息的物体类:
对于这种嵌套了别的类的类,使用列表初始化时数据也会是嵌套的,且顺序要保证按照定义类时使用的顺序:
由此可见,类中的类也可以被访问,方式同样是句点加成员名。不论嵌套多深的类,都可以间接地以这种方式访问。
类型别名与自定义类是很有效的数据组织手段,而本节仅仅起到敲门砖的作用。随着学习的深入,我们将在未来的实践中更加深入地熟悉与掌握它们。
Last updated