结构简介
假设要存储有关篮球运动员的信息,则可能需要存储他(她)的姓名、工资、身高、体重、平均得分、
命中率、助攻次数等。希望有一种数据格式可以将所有这些信息存储在一个单元中“数组不能完成这项任
务。因为虽然数组可以存储多个元素。但所有元素的类型必须相同。也就是说,一个数组可以存储20个
int,另一个数组可以存储10个float,但同一个数组不能在一些元素中存储int,在另一些元素中存储float。
C++中的结构的可以满足要求(存储篮球运动员的信息结构是一种比数组更灵活的数据格式,因为
同一个结构可以存储多种类型的数据,这使得能够将有关篮球运动员的信息放在一个结构中,从而将数据
的表示合并到一起。如果要跟踪整个球队,则可以使用结构数组。结构也是C++OOP堡垒(类)的基石。
学习有关结桷的知识将使我们离C++的核心OOP更近。
结构是用户定义的类型,而结构声明定义了这种类型的数据属性·定义了类型后,便可以创建这种类
型的变量。因此创建结构包括两步。首先,定义结构描述一一它描述并标记了能够存储在结构中的各种数
据类型。然后按描述创建结构变量(结构数据对象)。
例如。假设Bloataire公司要创建一种类型来描述其生产线上充气产品的成员。具体地说,这种类型应
存储产品名称、容鼠(单位为立方英尺)和售价。下面的结构描述能够满足这些要求:
struct inflatable //structure declaration { char name[20]; float volume; double price; };关键字struct表明,这些代码定义的是一个结构的布局。标识符inflatable是这种数据格式的名称,因此新类型的名称为inflatable。这样,便可以像创
建char或int类型的变量那样创建inflatable类型
的变量了。接下来的大括号中包含的是结构存储
的数据类型的列表,其中每个列表项都是一条声
明语句。这个例子使用了一个适合用于存储字符
串的char数组、一个float和一个double。列表
中的每一项都被称为结构成员,因此infatable结
构有3个成员(参见图4.6)。总之,结构定义指
出了新类型(这里是inflatable)的特征。
定义结构后,便可以创建这种类型的变量了:
struct inflatable //structure declaration { char name[20]; float volume; double price; }; intflatable hat; intflatable woopie_custhion; inflatable mainframe;如果您熟悉C语言中的结构,则可能己经注意到了,C++允许在声明结构变量时省略关键字struct:
struct inflatable goose; inflatable vincent;在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)的方式衍生而来的。
在程序中使用结构
// 结构简介.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> struct inflatable //structure declaration { char name[20]; float volume; double price; }; int main() { using namespace std; inflatable guest = { "Glorious Gloria", 1.88, 29.99 }; inflatable pal = { "Audacious Arthur", 3.12, 32.99 }; cout << "Expand your guest list with" << guest.name; cout << "and" << pal.name << "!\n"; cout << "You can have both for $"; cout << guest.price+pal.price<< " \n"; return 0; }运行结果
Expand your guest list withGlorious GloriaandAudacious Arthur! You can have both for $62.98程序说明
结构声明的位置很重要。对于structur.cpp而言,有两种选择。可以将声明放在main()函数中,紧跟在
开始括号的后面。另一种选择是将声明放到main()的前面,这里采用的便是这种方式,位于函数外面的声
明被称为外部声明。对于这个程序来说,两种选择之间没有实际区别。但是对于那些包含两个或更多函数
的程序来说,差别很大。外部声明可以被其后面的任何函数使用,而内部声明只能被该声明所属的函数使
用。通常应使用外部声明,这样所有函数都可以使用这种类型的结构(参见图4.7)。
变量也可以在函数内部和外部定义,外部变量由所有的函数共享(这将在第9章做更详细的介绍).
C++不提倡使用外部变量,但提倡使用外部结构声明。另外,在外部声明符号常量通常更合理。
接下来,请注意初始化方式:
inflatable guest= { "Glorious Gloria",//name value 1.88, //volume value 29.99 }和数组一样,使用由逗号分隔值列表,并将这些值用花括号括起。在该程序中,每个值占一行,但也可以将它们全部放在同一行中。只是应用逗号将它们分开:
inflatable duck={"Daphne",0.12,9.98}可以将结构的每个成员都初始化为适当类型的数据。例如,name成员是一个字符数组,因此可以将其
初始化为一个字符串。
可将每个结构成员看作是相应类型的变量。因此,pal.price是一个double变量,而pal.name是一个char
数组。当程序使用cout显示pal.name时,将把该成员显示为字符串。另外,由于pal.name是一个字符数组,
因此可以用下标来访问其中的各个字符。例如,pal.nam可[0]是字符A。不过pal[0]没有意义,因为pal是一
个结构,而不是数组。
C++11结构初始化
与数组一样,C++11也支持将列表初始化用于结构,且等号(=)是可选的:
inflatable duck{"Daphne",0.12,9.98}; //can omit the =in C++ 11其次,如果大括号内未包含任何东西,各个成员都栲被设置为零。例如,下面的声明导致mayor.price和mayor.volume
被置为零,且mayor.name的每个字节都被设置为零:
inflatable mayor{}最后,不允许缩窄转换。
结构可以将string类作为成员吗
可以将成员name指定为string对象而不是字符数组吗?即可以像下面这样声明结构吗?
#include<string> struct inflatable //structure definition { std::string name; float volume; double price; };答案是肯定的,只要您使用的编译器支持对以string对象作为成员的鲒构进行初始化。
一定要让结构定义能够访问名称空间。为此,可以将编译指令using移到结构定义之前:也可以像
前面那样,将name的类型声明为std:string?
其他结构属性
C++使用户定义的类型与内置类型尽可能相似。例如,可以将结构作为参数传递给函数,也可以让函
数返回一个结构。另外,还可以使用赋值运算符(=)将结构赋给另一个同类型的结构,这样结构中每个
成员都将被设置为另一个结构中相应成员的值,即使成员是数组。这种赋值被称为成员赋值(memberwise
assignment),将在第7章讨论函数时再介绍如何传递和返回结构。下面简要地介绍一下结构赋值,程序清
单4.12是一个这样的示例。
#include <iostream> struct inflatable { char name[20]; float volume; double price; }; int main() { using namespace std; inflatable bouquet = { "sunflowers", 0.20, 12.49 }; inflatable choice; cout << "bouquet:" << bouquet.name << "for $"; cout << bouquet.price << endl; choice = bouquet; //assign one structure to another cout << "choice:" << choice.name << "for $"; cout << choice.price << endl; return 0; }运行结果
bouquet:sunflowersfor $12.49 choice:sunflowersfor $12.49从中可以看出,成员赋值是有效的,因为choice结构的成员值与bouquet结构中存储的值相同。
可以同时完成定义结构和创建结构变量的工作。为此,只需将变量名放在结束括号的后面即可:
struct perks { int key_number; char car[12]; }mr_smith,ms_jones; //two perks variables甚至可以初始化以这种方式创建的变量:
struct perks { int key_number; char car[12]; }mr_glitz= { 7, "Packard" }然而,将结构定义和变量声明分开,可以使程序更易于阅读和理解。
还可以声明没有名称的结构类型,方法是省略名称,同时定义一种结构类型和一个这种类型的变量:
struct [ int x; int y; ]position;这样将创建一个名为position的结构变量。可以使用成员运算符来访问它的成员(如positton.x),但这
种类型没有名称,因此以后无法创建这种类型的变量。
除了C++程序可以使用结构标记作为类型名称外,C结构具有到目前为止讨论的C++结构的所有特性
(C++11特性除外),但C++结构的特性更多。例如,与C结构不同,C++结构除了成员变量之外,还可以
有成员函数。但这些高级特性通常被用于类中,而不是结构中,因此将在讨论类的时候(从第10章开始)。
结构数组
inflatable-结构包含一个数组(name)。也可以创建元素为结构的数组,方法和创建基本类型数组完全
相同。一例如,要创建一个包含一100个inflatable结构的数组,可以这样做:
inflatable gifts[100];//array of 100 inflatable structures这样,gifts将是一个inflatable数组,其中的每个元素(如gifts[0]或gifts[99]都是inflatable对象,可
以与成员运算符一起使用:
cin>>gifts[0].volume; //use volume member of first struct cout<<gifts[99].price<<endl;//display price member of last struct记住,gifts本身是一个数组,而不是结构,因此像gifts.price这样的表述是无效的。
要初始化结构数组,可以结合使用初始化数组的规則(用逗号分隔每个元素值,并将这些值用花括
号括起)和初始化结构的规则(用逗号分隔每个成员的值,并将这些值用花括号括起)。由于数组中的每个
元素都是结构,因此可以使用结构初始化的方式来提供它的值。因此,最终结果为一个被括在花括号中、
用逗号分隔的值列表,其中每个值木身又是一个被括在花括号中、用逗号分隔的值列表:
可以按自己喜欢的方式来格式化它们。例如,两个初始化位于同一行,而每个结构成员的初始化各占一行。
程序清单4.13是一个使用结构数组的简短示例。由于guests是一个inflatable数组,因此guests[0]的类
型为inflatable,可以使用它和句点运算符来访问相应inflatable结构的成员。
// 结构数组.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> struct inflatable { char name[20]; float volume; double price; }; int main() { using namespace std; inflatable guests[2] = { {"Bambi",0.5,21.99}, {"Godzilla",2000,565.99} }; cout << "The quests" << guests[0].name << "and" << guests[1].name << "\nhave a combined volume of" << guests[0].volume + guests[1].volume << "cubic feet.\n"; return 0; }运行结果
The questsBambiandGodzilla have a combined volume of2000.5cubic feet.结构中的位字段
与C语言一样,C++也允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上的寄存器对
应的数据结构非常方便。字段的类型应为整型或枚举(相后将介绍),接下来是冒号,冒号后面是一个数字。
它指定了使用的位数,可以使用没有名称的字段来提供间距。每个成员都被称为位字段(bit field)。下面
是一个例子:
struct torgle_register { unsigned int SN:4; unsigned int :4; bool goodIn:1; bool goodTorgle:1; };可以像通常那样初始化这些字段,还可以使用标准的结构表示法来访问位字段:
torgle_register tr={14,true,false}; ... if(tr.goodIn) ...位字段通常用在低级编程中。一般来说.可以使用整型和附录E介绍的按位运算符来代替这种方式。