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++中的作用——將有聯系的多個簡單事物打包成單個復雜事物,實現化繁為簡。