官术网_书友最值得收藏!

2.3 用戶自定義類型

用戶自定義類型(User-Defined Type)是用戶可以定義的類型。用戶自定義類型有三大類:

? 枚舉類型:最簡(jiǎn)單的用戶自定義類型。枚舉類型可以取的值被限制在一組可能的值中。枚舉類型是對(duì)分類概念進(jìn)行建模的最佳選擇。

? :功能更全面的類型,它使我們可以靈活地結(jié)合數(shù)據(jù)和函數(shù)。只包含數(shù)據(jù)的類被稱為普通數(shù)據(jù)類(Plain-Old-Data,POD),見2.3.2節(jié)。

? 聯(lián)合體:濃縮的用戶自定義類型。所有成員共享同一個(gè)內(nèi)存位置。聯(lián)合體本身很危險(xiǎn),容易被濫用。

2.3.1 枚舉類型

使用關(guān)鍵字enum class來(lái)聲明枚舉類型,關(guān)鍵字后面是類型名稱和它可以取的值的列表。這些值是任意的字母-數(shù)字字符串,代表任意想代表的類別。在實(shí)現(xiàn)內(nèi)部,這些值只是整數(shù),但它們?cè)试S使用程序員定義的類型而不是可能代表任何東西的整數(shù)來(lái)編寫更安全、更有表現(xiàn)力的代碼。例如,代碼清單2-13聲明了一個(gè)名為Race的枚舉類,它可以取七個(gè)值中的一個(gè)。

代碼清單2-13 一個(gè)包含尼爾·斯蒂芬森(Neal Stephenson)小說(shuō)《七夏娃》中所有種族的枚舉類

要將枚舉變量初始化為一個(gè)值,使用類型的名稱后跟兩個(gè)冒號(hào)::和所需的值即可實(shí)現(xiàn)。例如,下面的代碼展示了如何聲明變量langobard_race并將其初始化為Aidan

注意 從技術(shù)上講,枚舉類是兩種枚舉類型中的一種:它被稱為作用域枚舉。為了與C語(yǔ)言兼容,C++也支持非作用域枚舉類型,它是用enum而非enum class聲明的。主要的區(qū)別是,作用域枚舉需要在值前面加上枚舉類型和::,而非作用域枚舉則不需要。非作用域枚舉類比作用域枚舉類使用起來(lái)更不安全,所以除非絕對(duì)必要,否則請(qǐng)不要使用它們。C++支持它們主要是出于歷史原因,特別是基于與C代碼的互操作。詳情請(qǐng)參見Scott Meyers的Effective Modern C++的第10項(xiàng)。

1.switch語(yǔ)句

switch語(yǔ)句根據(jù)condition(條件)值將控制權(quán)轉(zhuǎn)移到幾個(gè)語(yǔ)句中的一個(gè),condition值可以是整數(shù)或枚舉類型的。switch關(guān)鍵字表示一個(gè)switch語(yǔ)句。

switch語(yǔ)句提供了條件性分支。當(dāng)switch語(yǔ)句執(zhí)行時(shí),控制權(quán)將轉(zhuǎn)移到符合條件的情況(case語(yǔ)句),如果沒(méi)有符合條件表達(dá)式的情況,則轉(zhuǎn)移到默認(rèn)情況。每個(gè)case關(guān)鍵字都表示一種情況,而default關(guān)鍵字表示默認(rèn)情況。

有點(diǎn)令人困惑的是,執(zhí)行過(guò)程將持續(xù)到switch語(yǔ)句結(jié)束或break關(guān)鍵字。幾乎總能在每個(gè)條件的末尾發(fā)現(xiàn)一個(gè)break。

switch語(yǔ)句有很多case語(yǔ)句。代碼清單2-14顯示了它們是如何組合在一起的。

代碼清單2-14 switch工作框架

所有的switch語(yǔ)句都以switch關(guān)鍵字?開始,后面緊跟著用括號(hào)括起來(lái)的條件(condition)?。每個(gè)case語(yǔ)句都以case關(guān)鍵字?開頭,后面跟著枚舉值或整數(shù)值?。例如,如果條件值?等于case-a?,那么包含Handle case a here的代碼塊將被執(zhí)行。在每條case語(yǔ)句之后?,都要放置break關(guān)鍵字?。如果條件值與所有case中的值都不匹配,則執(zhí)行默認(rèn)的情況default?。

注意 每個(gè)case的大括號(hào)可有可無(wú),但強(qiáng)烈推薦使用。沒(méi)有它們,有時(shí)會(huì)得到令人驚訝的行為。

2.對(duì)枚舉類使用switch語(yǔ)句

代碼清單2-15對(duì)Race枚舉類使用switch語(yǔ)句來(lái)生成定制的問(wèn)候語(yǔ)。

代碼清單2-15 一個(gè)根據(jù)所選種族打印問(wèn)候語(yǔ)的程序

enum class?聲明了枚舉類型Race,我們可以用它將race初始化為Dinan?。switch語(yǔ)句?評(píng)估條件race,以確定將控制權(quán)交給哪個(gè)case語(yǔ)句。因?yàn)橐言谇懊鎸?b>race硬編碼為Dinan,因此將執(zhí)行第一條case語(yǔ)句?,它將打印You work hard.。第一條case語(yǔ)句后的break?將終止switch語(yǔ)句。

default語(yǔ)句?是一個(gè)安全功能。如果有人在枚舉類中添加了新的race值,那么在運(yùn)行時(shí)將檢測(cè)到這個(gè)未知的race,并打印出錯(cuò)誤信息。

試著把race?設(shè)置為不同的值,看看輸出有什么變化?

2.3.2 普通數(shù)據(jù)類

類是用戶自定義的包含數(shù)據(jù)和函數(shù)的類型,它們是C++的核心和靈魂。最簡(jiǎn)單的類是普通數(shù)據(jù)類(Plain-Old-Data,POD)。POD是簡(jiǎn)單的容器。我們可以把它們看作一種潛在的不同類型的元素的異構(gòu)數(shù)組。類的每個(gè)元素都被稱為一個(gè)成員(member)。

每個(gè)POD都以關(guān)鍵詞struct開頭,后面跟著POD的名稱,再后面要列出成員的類型和名稱。考慮下面這個(gè)有四個(gè)成員的Book類聲明:

Book包含一個(gè)名為name?的char數(shù)組、一個(gè)int year?、一個(gè)int pages?和一個(gè)bool hardcover?。

聲明POD變量就像聲明其他變量一樣:通過(guò)類型和名稱。我們可以使用點(diǎn)運(yùn)算符(.)訪問(wèn)變量的成員。

代碼清單2-16使用了Book類型。

代碼清單2-16 使用POD類Book來(lái)讀寫成員的例子

首先,聲明一個(gè)Book變量neuromancer?。然后,使用點(diǎn)運(yùn)算符(.)將neuro-mancer的頁(yè)數(shù)設(shè)置為271?。最后,打印一條信息,并從neuromancer中提取頁(yè)數(shù),同樣使用點(diǎn)運(yùn)算符?。

注意 POD有一些有用的底層特性:它們與C語(yǔ)言兼容,我們可以使用高效的機(jī)器指令來(lái)復(fù)制或移動(dòng)它們,而且它們可以在內(nèi)存中有效地表示出來(lái)。

C++保證成員在內(nèi)存中是按順序排列的,盡管有些實(shí)現(xiàn)要求成員沿著字的邊界對(duì)齊,這取決于CPU寄存器的長(zhǎng)度。一般來(lái)說(shuō),應(yīng)該在POD定義中從大到小排列成員。

2.3.3 聯(lián)合體

聯(lián)合體(union)類似于POD,它把所有的成員放在同一個(gè)地方。我們可以把聯(lián)合體看作對(duì)內(nèi)存塊的不同看法或解釋。它們?cè)谝恍┑讓忧闆r下是很有用的,例如,處理必須在不同架構(gòu)下保持一致的結(jié)構(gòu)時(shí),處理與C/C++互操作有關(guān)的類型檢查問(wèn)題時(shí),甚至在包裝位域(bitfield)時(shí)。

代碼清單2-17說(shuō)明了如何聲明聯(lián)合體:用union關(guān)鍵字代替struct即可。

代碼清單2-17 一個(gè)聯(lián)合體的例子

聯(lián)合體Variant可以被解釋成char[10]int double。它占用的內(nèi)存與它最大的成員(在本例中可能是string)占用的內(nèi)存一樣多。

我們可以使用點(diǎn)運(yùn)算符(.)來(lái)指定聯(lián)合體的解釋。從語(yǔ)法上看,這看起來(lái)像訪問(wèn)POD的成員,但它在內(nèi)部是完全不同的。

因?yàn)槁?lián)合體的所有成員都在同一個(gè)地方,所以很容易造成數(shù)據(jù)損壞。代碼清單2-18說(shuō)明了這種危險(xiǎn)。

代碼清單2-18 使用代碼清單2-17中聯(lián)合體Variant的程序

首先,聲明Variant v?。接著,把v解釋為整數(shù),把它的值設(shè)置為42?,并打印它?。然后,把v重新解釋為浮點(diǎn)數(shù),重新賦值?,把它打印到控制臺(tái),一切看起來(lái)很好?。到目前為止還不錯(cuò)。

只有當(dāng)再次將v解釋為整數(shù)時(shí),災(zāi)難才會(huì)降臨?。在賦值為歐拉數(shù)?時(shí),會(huì)把v的原值(42)?給破壞了。

這就是聯(lián)合體存在的主要問(wèn)題:要靠程序員自己來(lái)跟蹤哪種解釋是合適的。編譯器不會(huì)提供幫助。

除了罕見的情況,應(yīng)該避免使用聯(lián)合體,本書中就不會(huì)使用它們。12.1.6節(jié)討論了當(dāng)需要多類型變量時(shí)應(yīng)選擇的一些更安全的選擇。

主站蜘蛛池模板: 仪陇县| 潢川县| 天祝| 西丰县| 晋城| 和顺县| 伽师县| 西盟| 布尔津县| 馆陶县| 额济纳旗| 深水埗区| 息烽县| 饶平县| 泾阳县| 长沙市| 乡城县| 大荔县| 尖扎县| 安阳市| 文登市| 钟祥市| 苍南县| 杂多县| 浮梁县| 桃园县| 双城市| 南雄市| 宽城| 广宗县| 永春县| 普兰县| 鄂尔多斯市| 峡江县| 来安县| 山阳县| 连州市| 昌吉市| 迁安市| 奈曼旗| 泗阳县|