返回介绍

4.4 结构简介

发布于 2024-10-08 23:14:02 字数 7250 浏览 0 评论 0 收藏 0

假设要存储有关篮球运动员的信息,则可能需要存储他(她)的姓名、工资、身高、体重、平均得分、命中率、助攻次数等。希望有一种数据格式可以将所有这些信息存储在一个单元中。数组不能完成这项任务,因为虽然数组可以存储多个元素,但所有元素的类型必须相同。也就是说,一个数组可以存储 20 个 int,另一个数组可以存储 10 个 float,但同一个数组不能在一些元素中存储 int,在另一些元素中存储 float。

C++中的结构的可以满足要求(存储篮球运动员的信息)。结构是一种比数组更灵活的数据格式,因为同一个结构可以存储多种类型的数据,这使得能够将有关篮球运动员的信息放在一个结构中,从而将数据的表示合并到一起。如果要跟踪整个球队,则可以使用结构数组。结构也是 C++ OOP 堡垒(类)的基石。学习有关结构的知识将使我们离 C++的核心 OOP 更近。

结构是用户定义的类型,而结构声明定义了这种类型的数据属性。定义了类型后,便可以创建这种类型的变量。因此创建结构包括两步。首先,定义结构描述—它描述并标记了能够存储在结构中的各种数据类型。然后按描述创建结构变量(结构数据对象)。

例如,假设 Bloataire 公司要创建一种类型来描述其生产线上充气产品的成员。具体地说,这种类型应存储产品名称、容量(单位为立方英尺)和售价。下面的结构描述能够满足这些要求:

关键字 struct 表明,这些代码定义的是一个结构的布局。标识符 inflatable 是这种数据格式的名称,因此新类型的名称为 inflatable。这样,便可以像创建 char 或 int 类型的变量那样创建 inflatable 类型的变量了。接下来的大括号中包含的是结构存储的数据类型的列表,其中每个列表项都是一条声明语句。这个例子使用了一个适合用于存储字符串的 char 数组、一个 float 和一个 double。列表中的每一项都被称为结构成员,因此 infatable 结构有 3 个成员(参见图 4.6)。总之,结构定义指出了新类型(这里是 inflatable)的特征。

图 4.6 结构描述的组成部分

定义结构后,便可以创建这种类型的变量了:

如果您熟悉 C 语言中的结构,则可能已经注意到了,C++允许在声明结构变量时省略关键字 struct:

在 C++中,结构标记的用法与基本类型名相同。这种变化强调的是,结构声明定义了一种新类型。在 C++中,省略 struct 不会出错。

由于 hat 的类型为 inflatable,因此可以使用成员运算符(.)来访问各个成员。例如,hat.volume 指的是结构的 volume 成员,hat.price 指的是 price 成员。同样,vincent.price 是 vincent 变量的 price 成员。总之,通过成员名能够访问结构的成员,就像通过索引能够访问数组的元素一样。由于 price 成员被声明为 double 类型,因此 hat.price 和 vincent.price 相当于是 double 类型的变量,可以像使用常规 double 变量那样来使用它们。总之,hat 是一个结构,而 hat.price 是一个 double 变量。顺便说一句,访问类成员函数(如 cin.getline( ))的方式是从访问结构成员变量(如 vincent.price)的方式衍生而来的。

4.4.1 在程序中使用结构

介绍结构的主要特征后,下面在一个使用结构的程序中使用这些概念。程序清单 4.11 说明了有关结构的这些问题,还演示了如何初始化结构。

程序清单 4.11 structur.cpp

下面是该程序的输出:

程序说明

结构声明的位置很重要。对于 structur.cpp 而言,有两种选择。可以将声明放在 main( ) 函数中,紧跟在开始括号的后面。另一种选择是将声明放到 main( ) 的前面,这里采用的便是这种方式,位于函数外面的声明被称为外部声明。对于这个程序来说,两种选择之间没有实际区别。但是对于那些包含两个或更多函数的程序来说,差别很大。外部声明可以被其后面的任何函数使用,而内部声明只能被该声明所属的函数使用。通常应使用外部声明,这样所有函数都可以使用这种类型的结构(参见图 4.7)。

图 4.7 局部结构声明和外部结构声明

变量也可以在函数内部和外部定义,外部变量由所有的函数共享(这将在第 9 章做更详细的介绍)。C++不提倡使用外部变量,但提倡使用外部结构声明。另外,在外部声明符号常量通常更合理。

接下来,请注意初始化方式:

和数组一样,使用由逗号分隔值列表,并将这些值用花括号括起。在该程序中,每个值占一行,但也可以将它们全部放在同一行中。只是应用逗号将它们分开:

可以将结构的每个成员都初始化为适当类型的数据。例如,name 成员是一个字符数组,因此可以将其初始化为一个字符串。

可将每个结构成员看作是相应类型的变量。因此,pal.price 是一个 double 变量,而 pal.name 是一个 char 数组。当程序使用 cout 显示 pal.name 时,将把该成员显示为字符串。另外,由于 pal.name 是一个字符数组,因此可以用下标来访问其中的各个字符。例如,pal.name[0]是字符 A。不过 pal[0]没有意义,因为 pal 是一个结构,而不是数组。

4.4.2 C++11 结构初始化

与数组一样,C++11 也支持将列表初始化用于结构,且等号(=)是可选的:

其次,如果大括号内未包含任何东西,各个成员都将被设置为零。例如,下面的声明导致 mayor.volume 和 mayor.price 被设置为零,且 mayor.name 的每个字节都被设置为零:

最后,不允许缩窄转换。

4.4.3 结构可以将 string 类作为成员吗

可以将成员 name 指定为 string 对象而不是字符数组吗?即可以像下面这样声明结构吗?

答案是肯定的,只要您使用的编译器支持对以 string 对象作为成员的结构进行初始化。

一定要让结构定义能够访问名称空间 std。为此,可以将编译指令 using 移到结构定义之前;也可以像前面那样,将 name 的类型声明为 std::string。

4.4.4 其他结构属性

C++使用户定义的类型与内置类型尽可能相似。例如,可以将结构作为参数传递给函数,也可以让函数返回一个结构。另外,还可以使用赋值运算符(=)将结构赋给另一个同类型的结构,这样结构中每个成员都将被设置为另一个结构中相应成员的值,即使成员是数组。这种赋值被称为成员赋值(memberwise assignment),将在第 7 章讨论函数时再介绍如何传递和返回结构。下面简要地介绍一下结构赋值,程序清单 4.12 是一个这样的示例。

程序清单 4.12 assgn_st.cpp

下面是该程序的输出:

从中可以看出,成员赋值是有效的,因为 choice 结构的成员值与 bouquet 结构中存储的值相同。

可以同时完成定义结构和创建结构变量的工作。为此,只需将变量名放在结束括号的后面即可:

甚至可以初始化以这种方式创建的变量:

然而,将结构定义和变量声明分开,可以使程序更易于阅读和理解。

还可以声明没有名称的结构类型,方法是省略名称,同时定义一种结构类型和一个这种类型的变量:

这样将创建一个名为 position 的结构变量。可以使用成员运算符来访问它的成员(如 position.x),但这种类型没有名称,因此以后无法创建这种类型的变量。本书将不使用这种形式的结构。

除了 C++程序可以使用结构标记作为类型名称外,C 结构具有到目前为止讨论的 C++结构的所有特性(C++11 特性除外),但 C++结构的特性更多。例如,与 C 结构不同,C++结构除了成员变量之外,还可以有成员函数。但这些高级特性通常被用于类中,而不是结构中,因此将在讨论类的时候(从第 10 章开始)介绍它们。

4.4.5 结构数组

inflatable 结构包含一个数组(name)。也可以创建元素为结构的数组,方法和创建基本类型数组完全相同。例如,要创建一个包含 100 个 inflatable 结构的数组,可以这样做:

这样,gifts 将是一个 inflatable 数组,其中的每个元素(如 gifts[0]或 gifts[99])都是 inflatable 对象,可以与成员运算符一起使用:

记住,gifts 本身是一个数组,而不是结构,因此像 gifts.price 这样的表述是无效的。

要初始化结构数组,可以结合使用初始化数组的规则(用逗号分隔每个元素的值,并将这些值用花括号括起)和初始化结构的规则(用逗号分隔每个成员的值,并将这些值用花括号括起)。由于数组中的每个元素都是结构,因此可以使用结构初始化的方式来提供它的值。因此,最终结果为一个被括在花括号中、用逗号分隔的值列表,其中每个值本身又是一个被括在花括号中、用逗号分隔的值列表:

可以按自己喜欢的方式来格式化它们。例如,两个初始化位于同一行,而每个结构成员的初始化各占一行。

程序清单 4.13 是一个使用结构数组的简短示例。由于 guests 是一个 inflatable 数组,因此 guests[0]的类型为 inflatable,可以使用它和句点运算符来访问相应 inflatable 结构的成员。

程序清单 4.13 arrstruc.cpp

下面是该程序的输出:

4.4.6 结构中的位字段

与 C 语言一样,C++也允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上的寄存器对应的数据结构非常方便。字段的类型应为整型或枚举(稍后将介绍),接下来是冒号,冒号后面是一个数字,它指定了使用的位数。可以使用没有名称的字段来提供间距。每个成员都被称为位字段(bit field)。下面是一个例子:

可以像通常那样初始化这些字段,还可以使用标准的结构表示法来访问位字段:

位字段通常用在低级编程中。一般来说,可以使用整型和附录 E 介绍的按位运算符来代替这种方式。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文