结构
假如要存储有关篮球运动员的信息,则可能需要存储他的姓名、身高、体重、平均得分、命中率、助攻次数等。希望有一种数据格式可以将所有这些信息存储在一个单元中。用数组无法完成这项任务,因为数组虽然可以存储多个元素,但所有元素必须类型相同,也就是说,不能在同一个数组中既存储int,又存储float。
C++中的结构可以满足要求。结构是一种比数组更加灵活的数据格式,同一个结构可以存储多种类型的数据。
结构是用户定义的类型,结构声明定义了这种类型的数据属性。
创建结构包括两步:
- 定义结构描述:描述并标记能够存储在结构中的各种数据类型;
- 按描述创建结构变量(结构数据对象)。
假设某公司要创建一种类型来描述某种充气产品(书上举得什么例子……),这种类型应存储产品名称、容量、售价,下面的结构描述能够满足这些要求:
struct inflatable
{
char name[20];
float volume;
double price;
};
关键字struct表明这些代码定义的是一个结构,inflatable是这种数据格式的名称,因此新类型的名称为inflatable。这样便可以像创建char、int类型的变量那样创建inflatable类型的变量。
大括号中包含的是结构存吃的数据类型的列表,其中每个列表项都是一条声明语句。列表中的每一项都被称为结构成员。总之,结构定义指出了新类型(inflatable)的特征。
定义结构后,便可以创建这种类型的变量了:
inflatable hat; //hat是一个inflatable类型的结构变量
inflatable woopie_cushion;
inflatable mainframe;
与C语言不同的是,C++允许在声明结构变量时省略关键字struct:
struct inflatable goose; //关键字struct在C语言中不可省略
inflatable vincent; //关键字struct在C++中可以省略
在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.get())的方式是从访问结构成员变量(如hat.price)的方式衍生出来的。
1. 在程序中使用结构
程序4.11
#include<iostream>
struct inflatable
{
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";
cin.get();
return 0;
}
结构声明的位置很重要,程序4.11有两种选择:可以将声明放在main()函数中,紧跟在{后,这种声明称为内部声明;也可以将声明放在main()函数前(如4.11所示),这种声明被称为外部声明。
对于包含两个或者更多函数的程序来说,外部声明可以被其后面的任何函数使用,而内部声明只能被该声明所属的函数使用。通常应使用外部声明,这样所有的函数都可使用这种类型的结构。
变量也可以在函数内部和外部定义,外部变量由所有的函数共享。C++不提倡使用外部变量,但提倡使用外部结构声明。另外,在外部声明符号常量通常更合理。
初始化方式:
inflatable guest =
{
"Glorious Gloria",
1.88,
29.99
};
和数组一样,使用逗号分隔值列表,并将这些值用{}括起。在这里每个值占一行,但也可以将它们全部放在同一行,只用逗号将他们分开:
inflatable guest ={"Glorious Gloria",1.88,29.99};
可将结构的每个成员都初始化为适当类型的数据。例如,name成员是一个字符数组,因此可以将其初始化为一个字符串。
可将每个结构成员看作是相应类型的变量。因此,pal.price是一个double变量,pal.name是一个char数组。当程序使用cout显示pal.name时,将把改成员显示为字符串。由于pal.name是一个字符数组美因此可以用下标来访问各个字符,例如,pal.name[0]是字符A,不过pal[0]没有意义。
2. C++11结构初始化
- 与数组一样,C++11也支持将列表初始化用于结构,且=是可选的:
inflatable duck {"Daphne, 0.12, 9.98};
- 如果大括号内未包含任何东西,各个成员都将被置为零:
inflatable mayor {}; //该声明导致mayor.volume和mayor.price被设置为0,mayor.name的各个字节都被设为0
- 不允许缩窄转换
3. 结构可以将string类作为成员
可以将成员name指定为string对象而不是字符数组:
#include<string>
struct inflatable
{
std::string name;
float volume;
double price;
};
4. 其他结构属性
程序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; //将一个结构赋值给另一个
cout << "choice: " << choice.name << " fot $";
cout << choice.price << endl;
cin.get();
return 0;
}
程序4.12说明,成员赋值是有效的,因为choice结构的成员值与bouquet结构中存储的值相同。
可以同时完成定义结构和创建结构变量的工作,只需将变量名放在结束括号}的后面即可:
struct perks
{
int key_number;
char car[12];
} mr_smith, ms_jones; //两个perks变量
也可以初始化以这种方式创建的变量:
struct perks
{
int key_number;
char car[12];
} mr_glitz =
{
7,
"Packard"
};
但是,将结构定义和变量声明分开,更易于阅读和理解。
还可以声明没有名称的结构类型,方法是省略名称,同时定义一种结构类型和一个这种类型的变量:
struct //没有名称
{
int x; //两个成员
int y;
} position; //一个结构变量
除了C++可以使用结构标记作为类型名称(即省略struct)外,C机构具有上述所有C++(非C++11)结构特性。
5. 结构数组
inflatable结构包含一个数组(name)。也可以创建元素为结构的数组,方法和创建基本类型数组完全相同。例如,要创建一个包含100个inflatable结构的数组,可以:
inflatable gifts[100]; //包含100个inflatable结构的数组
这样,gifts将是一个inflatable数组,其中每个元素(gifts[0]到gifts[99])都是inflatable对象,可以与成员运算符一起使用:
cin>>gifts[0].volume;
cout<<gifts[99].price<<endl;
注意:gifts本身是一个数组,而不是结构,因此像gifts.price这样的表述是无效的。
初始化结构数组可以结合初始化数组的规则和初始化结构的规则:
inflatable guest[2] =
{
{"Bambi",0.5,21.99},
{"Godzilla",2000,565.99},
};
程序4.13
#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 guests " << guests[0].name << " and " << guests[1].name
<< "\nhave a combined volume of "
<< guests[0].volume + guests[1].volume << " cubic feet.\n";
cin.get();
return 0;
}
6. 结构中的位字段
与C语言一样,C++也允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上的寄存器对应的数据结构非常方便。字段的类型应为整型或枚举,接下来是冒号,冒号后面是一个数字,该数字制定了使用的位数。可以使用没有名称的字段来提供间距。每个成员都被称为位字段(bit field)。例如:
struct torgle_register
{
unsigned int SN : 4; //SN值占 4 bits
unsigned int : 4; //没有名称,提供4 bits间距
bool goodIn : 1;
bool goodTorgle : 1;
};
可以像通常那样初始化这些字段,还可以使用标准的结构表示法来访问位字段:
torgle_register tr = {14, true, false};
...
if (tr.goodIn)
...
位字段通常用在低级编程中。一般来说,可以使用整型和按位运算符来代替这种方式。