其他数据类型

类型别名 (typedef / using)

类型别名是可用于标识某个类型的另一个名称。在 C++ 中,任何有效的类型都可以被别名化,以便用不同的标识符来引用它。

在 C++ 中,有两种语法可以创建此类类型别名:第一种继承自 C 语言,使用 typedef 关键字。

typedef 现有类型 新类型名 ;

其中,existing_type 是任何类型,无论是基本类型还是复合类型,new_type_name 是赋予该类型的新名称的标识符。

例如:

1
2
3
4
typedef char C;
typedef unsigned int WORD;
typedef char * pChar;
typedef char field [50];

这定义了四个类型别名:CWORDpCharfield,它们分别是 charunsigned intchar*char[50] 的别名。一旦定义了这些别名,它们就可以在任何声明中使用,就像任何其他有效类型一样。

1
2
3
4
C mychar, anotherchar, *ptc1;
WORD myword;
pChar ptc2;
field name;

最近,C++ 语言引入了第二种定义类型别名的语法。

1
using new_type_name = existing_type ;

例如,与上面相同的类型别名可以定义为:

1
2
3
4
using C = char;
using WORD = unsigned int;
using pChar = char *;
using field = char [50];

typedef 定义的别名和用 using 定义的别名在语义上是等价的。唯一的区别是 typedef 在模板领域有某些限制,而 using 没有。因此,using 更通用,尽管 typedef 历史更长,并且在现有代码中可能更常见。

请注意,typedefusing 都不会创建新的、独立的数据类型。它们只为现有类型创建同义词。这意味着上面用 WORD 类型声明的 myword,其类型也可以被认为是 unsigned int;这并不重要,因为两者实际上都指向同一个类型。

类型别名可用于缩短冗长或令人困惑的类型名称,但它们作为将程序从其使用的底层类型中抽象出来的工具最为有用。例如,通过使用 int 的别名来指代特定类型的参数,而不是直接使用 int,可以在将来的版本中轻松地将该类型替换为 long(或其他类型),而无需更改每个使用它的地方。

联合 (Unions)

联合允许内存的同一部分作为不同的数据类型进行访问。其声明和使用方式与结构体相似,但功能完全不同。


union type_name {
  member_type1 member_name1;
  member_type2 member_name2;
  member_type3 member_name3;
  .
  .
} object_names;


这将创建一个新的、由 type_name 标识的联合类型,其中所有成员元素都占用内存中相同的物理空间。此类型的大小是其最大成员元素的大小。例如:

1
2
3
4
5
union mytypes_t {
  char c;
  int i;
  float f;
} mytypes;

声明了一个对象(mytypes),它有三个成员:

1
2
3
mytypes.c
mytypes.i
mytypes.

这些成员中的每一个都是不同的数据类型。但由于它们都指向内存中的同一位置,因此修改其中一个成员将影响所有成员的值。无法在它们中存储不同的值,并让每个值都与其他值相互独立。

联合的用途之一是能够以整体形式或作为由更小元素组成的数组或结构体来访问一个值。例如:

1
2
3
4
5
6
7
8
union mix_t {
  int l;
  struct {
    short hi;
    short lo;
    } s;
  char c[4];
} mix;

如果我们假设运行该程序的系统 int 类型的大小为 4 字节,short 类型的大小为 2 字节,那么上面定义的联合允许访问同一组 4 字节:mix.lmix.smix.c,我们可以根据我们想要如何访问这些字节来使用它们:就像它们是 int 类型的单个值,或者像它们是两个 short 类型的值,或者分别是一个 char 元素的数组。该示例在联合中混合了类型、数组和结构体,以演示访问数据的不同方式。对于小端系统,这个联合可以表示为:


联合成员在内存中的确切对齐方式和顺序取决于系统,这可能导致可移植性问题。

匿名联合 (Anonymous unions)

当联合是类(或结构体)的成员时,它们可以被声明为没有名称。在这种情况下,它们成为匿名联合,其成员可以直接通过成员名从对象访问。例如,请看以下两个结构体声明之间的区别:

带有常规联合的结构体带有匿名联合的结构体
struct book1_t {
char title[50];
char author[50];
union {
float dollars;
int yen;
} price;
} book1;
struct book2_t {
char title[50];
char author[50];
union {
float dollars;
int yen;
};
} book2;

这两种类型之间唯一的区别是,在第一种类型中,成员联合有一个名称(price),而在第二种类型中则没有。这影响了访问此类型对象的成员 dollarsyen 的方式。对于第一种类型的对象(带有常规联合),访问方式为:

1
2
book1.price.dollars
book1.price.

而对于第二种类型的对象(带有匿名联合),访问方式为:

1
2
book2.dollars
book2.

再次提醒,因为它是一个成员联合(而不是成员结构体),成员 dollarsyen 实际上共享相同的内存位置,因此它们不能用于同时存储两个不同的值。price 可以用 dollarsyen 设置,但不能同时使用两者。

枚举类型 (enum)

枚举类型是通过一组自定义标识符(称为枚举成员)作为可能值来定义的类型。这些枚举类型的对象可以取任何这些枚举成员作为其值。

其语法是:


enum type_name {
  value1,
  value2,
  value3,
  .
  .
} object_names;


这将创建一个名为 type_name 的类型,它可以取 value1value2value3 等中的任何一个作为值。该类型的对象(变量)可以直接实例化为 object_names

例如,可以定义一种名为 colors_t 的新变量类型来存储颜色,其声明如下:

1
enum colors_t {black, blue, green, cyan, red, purple, yellow, white};

注意,此声明的定义中不包含任何其他类型,无论是基本类型还是复合类型。换句话说,这在某种程度上是凭空创建了一个全新的数据类型,而没有基于任何其他现有类型。这种新类型 color_t 的变量可能取的值是在大括号内列出的枚举成员。例如,一旦声明了 colors_t 枚举类型,以下表达式将是有效的:

1
2
3
4
colors_t mycolor;
 
mycolor = blue;
if (mycolor == green) mycolor = red;

enum 声明的枚举类型的值可以隐式转换为整数类型。事实上,这样的 enum 的元素在内部总是被赋予一个等效的整数数值,并且它们可以被隐式转换为该数值。如果没有另外指定,第一个可能值对应的整数值为 0,第二个为 1,第三个为 2,依此类推……因此,在上面定义的 colors_t 数据类型中,black 等效于 0blue 等效于 1green 等效于 2,依此类推……

可以为枚举类型中的任何可能值指定一个特定的整数值。如果它后面的常量值本身没有被赋予自己的值,则它自动被假定为前一个值加一。例如:

1
2
3
enum months_t { january=1, february, march, april,
                may, june, july, august,
                september, october, november, december} y2k;

在这种情况下,枚举类型 months_t 的变量 y2k 可以包含从 januarydecember 的 12 个可能值中的任何一个,这些值等效于 112 之间的整数值(而不是 011,因为 january 已被设为等于 1)。

带 enum class 的枚举类型

但是,在 C++ 中,可以创建真正的 enum 类型,它们既不能隐式转换为 int,其枚举成员值也不是 int 类型,而是 enum 类型本身,从而保持了类型安全。它们使用 enum class(或 enum struct)而不是简单的 enum 来声明。

1
enum class Colors {black, blue, green, cyan, red, purple, yellow, white};

enum class 类型的每个枚举成员值都需要限定在其类型作用域内(这实际上也适用于 enum 类型,但只是可选的)。例如:

1
2
3
4
Colors mycolor;
 
mycolor = Colors::blue;
if (mycolor == Colors::green) mycolor = Colors::red;

enum class 声明的枚举类型对其底层类型也有更多的控制;它可以是任何整型数据类型,如 charshortunsigned int,这主要用于确定该类型的大小。这通过在枚举类型名称后加冒号和底层类型来指定。例如:

1
enum class EyeColor : char {blue, green, brown};

这里,Eyecolor 是一个独立的类型,其大小与 char 相同(1 字节)。
Index
目录