第13章总结
本节阅读量:章节回顾
程序定义类型(也称为用户定义类型)是一种自定义类型,我们可以创建它以在自己的程序中使用。枚举类型和类类型(包括结构体、类和联合)允许创建程序定义的类型。
必须先定义程序定义的类型,然后才能使用它们。程序定义类型的定义称为类型定义。类型定义不受单定义规则的约束。
枚举(也称为枚举类型)是一种复合数据类型,其中每个可能的值都定义为符号常量(称为枚举元素)。不同枚举是不同的类型,这意味着编译器可以将它们与其他类型区分开来(与类型别名不同)。
非限定作用域枚举之所以如此命名,是因为它们将其枚举元素名称放入与枚举定义本身相同的作用域中(而不是像命名空间那样创建新的作用域)。它也会为其枚举元素提供作用域。非限定作用域枚举会隐式转换为整数值。
限定作用域枚举的工作方式类似于非限定作用域枚举,但不会隐式转换为整数,并且枚举元素仅放在枚举的作用域中(而不是放在定义枚举的作用域中)。
struct(structure的缩写)是一种程序定义的数据类型,它允许将多个变量绑定到一个类型中。作为结构体(或类)一部分的变量称为数据成员(或成员变量)。为了访问特定成员变量,可以在结构体变量名称和成员名称之间使用成员选择操作符(operator.,用于普通结构体和引用),或者使用指针操作符(operator->,用于结构体指针)。
在一般编程中,聚合数据类型(也称为聚合)是可以包含多个数据成员的任何类型。在C++中,只有C样式数组和结构体是聚合类型。
聚合可以使用一种称为聚合初始化的初始化形式,它允许直接初始化聚合的成员。为此,需要提供一个初始化列表,也就是一个由逗号分隔值组成的列表。聚合初始化执行成员级初始化,这意味着结构体中的每个成员都是按声明顺序初始化的。
在C++20中,指定初始值设定项允许您显式定义哪些初始化值映射到哪些成员。成员必须按照在结构中声明的顺序进行初始化,否则将导致错误。
当定义结构体(或类)类型时,可以为每个成员提供默认的初始化值,作为类型定义的一部分。该过程称为非静态成员初始化,初始化值称为成员默认初始值设定项。
出于性能原因,编译器有时会在结构体中添加间隙(这称为填充),因此结构体的大小可能大于其成员大小的总和。
类模板是用于实例化类类型(结构体、类或联合)的模板定义。类模板参数推导(CTAD)是C++17的一个功能,它允许编译器从初始值设定项中推导模板类型参数。
习题
问题 1
在设计一个游戏时,我们决定加入怪物,因为大家都喜欢打怪物。请声明一个表示怪物的结构体。怪物的类型可以是下列之一:ogre、dragon、orc、giant spider或slime。
每个怪物还应当有一个名字(使用std::string),以及一个表示它在死亡前能承受多少伤害的生命值。编写一个名为printMonster()的函数,打印该结构体的所有成员。实例化一个ogre和一个slime,使用初始化列表初始化它们,并把它们传给printMonster()。
程序应当产生如下输出:
This Ogre is named Torg and has 145 health.
This Slime is named Blurp and has 23 health.
查看答案
|
|
问题 2
指出下列各种类型的对象应当按值传递、按const地址传递还是按const引用传递。可以假设接受这些类型形参的函数不会修改它们。
a) char
查看答案
char是基本类型,因此应当按值传递。
b) std::string
查看答案
std::string每次被拷贝时都必须创建字符串的副本,因此按const引用传递。
c) unsigned long
查看答案
unsigned long是基本类型,因此应当按值传递。
d) bool
查看答案
bool是基本类型,因此应当按值传递。
e) 枚举类型
查看答案
枚举类型保存的是整数值(通常是int)。由于整数值按值传递,枚举类型也应当按值传递。
f)
|
|
查看答案
Position是结构体类型,应当按const引用传递。
g)
|
|
查看答案
虽然Player目前只包含一个int,按值传递会很快,但将来还会加入更多成员。我们不希望到时再去修改每一处使用Player的地方,因此按const引用传递。
h) int(当null是一个合法实参时)
查看答案
通常int会按值传递,但如果还希望能够传递一个「空」值,那么按地址传递是个好选择,因为既可以传入int的地址,也可以传入nullptr。
i) std::string_view
查看答案
std::string_view不会创建所观察字符串的副本,而且拷贝开销很小,因此按值传递。
问题 3
创建一个名为Triad的类模板,其中包含3个相同模板类型的成员。再创建一个名为print的函数模板,用于打印Triad。下面这个程序应当能够编译:
|
|
并产生如下结果:
[1, 2, 3][1.2, 3.4, 5.6]
如果你使用的是C++17,需要为CTAD提供一个推导指引才能正常工作(参见「13.11 类模板参数推导(CTAD)」)。
查看答案
|
|