你好,C++(14)如何描述“一个名叫陈良乔,年龄33岁,身高173厘米,体重61.5千克的男人”——3.8 用结构体类型描述复杂的事物
3.8 用结构体类型描述复杂的事物
利用C++本身所提供的基本数据类型所定义的变量,只能表达一些简单的事物。比如我们可以用int类型定义nAge变量表示人的年龄,用string类型定义strName变量表示人的姓名。然而,现实世界是复杂的,仅仅使用基本数据类型是不足以描述这个复杂的现实世界的。例如,我们无法使用某个基本数据类型来描述人这个复杂事物,因为他不仅有姓名,还有身高、年龄和性别等属性需要描述。但是我们注意到,再复杂的事物也是由简单事物组成的。既然我们能用基本数据类型来描述简单事物,那么把这些基本数据类型组合起来,形成一个可以描述同一事物多个不同属性的构造型数据类型,不就可以用来描述复杂事物了吗? 正是基于这样的想法,C++提供了结构体机制。
3.8.1 结构体的定义
在C++中,我们用struct关键字来将多个基本数据类型打包成结构体,其语法格式如下:
struct 结构体名 { 数据类型1 成员名1; 数据类型2 成员名2; // ... 数据类型n 成员名n; };
其中,struct关键字表示要创建一个结构体;结构体名就是要创建的结构体的名字,通常使用结构体描述的事物作为结构体的名字。比如,我们要创建的结构体是用来描述人这个复杂事物的,那么结构体的名字就可以使用Human;在结构体定义的内部,分别使用多个不同数据类型的变量来表示复杂事物的各个属性。比如,我们可以用string类型的m_strName变量来描述人的姓名,用bool类型的m_bMale变量来描述人的性别等等。因为这些变量共同组成了结构体,所以这些变量也被称为结构体的成员变量。了解了这些,我们就可以按照如下的方式来定义表示人这个复杂事物的Human结构体:
// 定义结构体Human描述人这个复杂事物 struct Human { string m_strName; // 姓名 bool m_bMale; // 性别 int m_nAge; // 年龄 int m_nHeight; // 身高 float m_fWeight; // 体重 };
通过结构体将描述一个复杂事物多个属性的多个变量打包在一起之后,我们就可以用这个结构体定义变量来描述这个复杂事物:
// 定义一个Human结构体变量描述陈良乔这个人 // 这个结构体包含了他的姓名、性别和年龄等信息 Human chenlq;
图3-5 将复杂事物打包成结构体
3.8.2 结构体的使用
结构体是多个基本数据类型的组合,自然结构体变量就是结构体中多个成员变量的组合,只要有了一个结构体变量,就等同于我们同时有了多个成员变量。进而,我们可以通过“.”符号来引用一个结构体变量中各个成员变量,利用它们来描述一个复杂事物的各个属性。比如,我们可以利用上面定义的Human结构体来描述“一个名叫陈良乔,年龄33岁,身高173厘米,体重61.5千克的男人”这一复杂事物:
// 定义一个Human类型变量chenlq, // 用来描述人这个复杂事物 Human chenlq; // 这个人的姓名是“陈良乔” chenlq.m_strName = "陈良乔"; // 年龄23岁 chenlq.m_nAge = 33; // 身高173 chenlq.m_nHeight = 173; // 体重61.5 chenlq.m_fWeight = 61.5; // 男人 chenlq.m_bMale = true;
这里我们注意到,如果想用结构体变量来描述一个复杂事物,只需要用“.”符号引用这个结构体变量中的各个成员变量,然后分别将这个复杂事物的各个属性对应地赋值给成员变量就可以了。比如,我们要表示这个人的姓名是“陈良乔”,只需要将这个字符串数据赋值给“.”引出的chenlq结构体变量中表示姓名的m_strName成员变量即可。其他属性,也都可以以此类推。
这里还需要提到的是,使用“.”引用的结构体成员变量,跟直接使用一个独立变量并没有太大差别,我们可以把它当作一个普通变量一样地进行读写访问。例如:
// 对结构体中的m_strName成员变量进行读写访问 // 写访问:为成员变量赋值 chenlq.m_strName = "陈良乔"; // 读访问:输出成员变量 cout<<"这个人的姓名是:"<<chenlq.m_strName<<endl;
有了结构体机制,我们就可以描述更加复杂的事物,解决更加复杂的问题。在前面的例子中,我们曾经创建了一个数组arrSalary来保存员工的工资,如果我们希望程序同时还能够处理员工的姓名、性别、年龄等附加的人事信息。如果没有结构体的帮助,我们不得不创建多个数组来分别保存这些附加信息,代码应该是这样的:
// 定义员工数据个数 const int NUM = 100000; // 定义保存姓名数据的数组 string arrName[NUM]; // 定义保存年龄数据的数组 int arrAge[NUM]; // 定义保存性别数据的数组 bool arrMale[NUM]; // 定义保存工资数据的数组 int arrSalary[NUM];
这样的代码虽然也能够解决问题,但是它有一个显著的缺点,那就是描述同一个事物的各种数据是相互分割独立的,丢失了它们之间的紧密联系。如果各个数组不是按照相同的顺序保存员工的各项数据,想要知道名字为“Chen Liangqiao”的这位员工的工资,就成了一件不可能完成的任务。
而有了结构体,我们就可以把描述同一个员工的所有相关信息,包括姓名、性别、年龄和工资等多个属性打包成一个结构体类型,然后用这个结构体类型来定义保存员工数据的数组,这样做不仅代码简单,而且上面那不可能完成的任务也可以轻松完成:
// 将描述“员工”这个复杂事物的多个属性的变量打包成一个结构体 struct Employee { string m_strName; // 姓名 bool m_bMale; // 性别 int m_nAge; // 年龄 int m_nSalary; // 工资 }; //… // 员工工资数据个数 const int NUM = 100000; // 定义保存员工数据的数组 Employee arrEmp[NUM]; // 利用for循环结构遍历数组,找到名为“Chen Liangqiao”的员工的工资 // for循环结构参考后文4.3.3小节的介绍 for(int i = 0;i < NUM; ++i) { // 如果数组中某个元素的m_strName成员变量的值是“Chen Liangiqoa” if("Chen Liangqiao" == arrEmp[i].m_strName) { // 输出此元素的名字和工资 cout<<arrEmp[i].m_strName <<"的工资是"<<arrEmp[i].m_nSalary<<endl; } }
在这段代码中,通过结构体的使用,我们将描述员工信息的多个变量打包成一个Employee结构体,然后,仅仅定义了一个Employee类型的数组,就代替了原来的四个数组,而这正体现了结构体在C++中的作用——将有联系的多个简单事物打包成单个复杂事物,实现化繁为简。