C++中的類(lèi)描述了一個(gè)對(duì)象類(lèi)型。一個(gè)對(duì)象包括數(shù)據(jù)成員(data member)和函數(shù)成員(function member)。換句話(huà)說(shuō)就是,它是由跟它相關(guān)聯(lián)的數(shù)據(jù)和函數(shù)組成的一個(gè)struct結(jié)構(gòu)體??紤]在圖 7.13中定義的那個(gè)簡(jiǎn)單的類(lèi)。一個(gè)Simple類(lèi)型的變量非常類(lèi)似于包含一個(gè)int成員的標(biāo)準(zhǔn)Cstruct結(jié)構(gòu)體。這些函數(shù)并不會(huì)儲(chǔ)存到指定結(jié)構(gòu)體的內(nèi)存中。但是,成員函數(shù)和其它函數(shù)是不一樣的。
它們傳遞了一個(gè)隱藏的參數(shù)。這個(gè)參數(shù)是一個(gè)指向成員函數(shù)能起作用的對(duì)象的指針。 例如,考慮圖 7.13中的Simple類(lèi)的成員函數(shù)set_data。如果用C語(yǔ)言來(lái) 書(shū)寫(xiě)此函數(shù),這個(gè)函數(shù)將像這樣:明確傳遞一個(gè)指向成員函數(shù)能起作用的 對(duì)象的指針,如圖 7.14所示。使用DJGPP編譯器加上-S選項(xiàng)(gcc和Borland編 譯器也是一樣)來(lái)告訴編譯器輸出一個(gè)包含此代碼產(chǎn)生的等價(jià)的匯編語(yǔ) 言代碼的源文件。對(duì)于DJGPP和gcc編譯器,此匯編源文件是以.s擴(kuò)展 名結(jié)尾的,但是不幸的是使用的語(yǔ)法是AT&T匯編語(yǔ)言語(yǔ)法,這種語(yǔ)法 和NASM和MASM語(yǔ)法區(qū)別非常大。(Borland和MS編譯器產(chǎn)生一個(gè)以.asm擴(kuò)展名結(jié)尾的源文件,使用的是MASM語(yǔ)法。)
圖 7.15展示了將DJGPP的輸 出轉(zhuǎn)換成NASM語(yǔ)法后的代碼,增加了闡明語(yǔ)句目的的注釋。在第一行 中,注意成員函數(shù)set_data的函數(shù)名被指定為一個(gè)改編后的標(biāo)號(hào),此標(biāo)號(hào) 是通過(guò)編碼成員函數(shù)名,類(lèi)名和參數(shù)后得到的。類(lèi)名被編碼進(jìn)去的是因?yàn)?其它類(lèi)中可能也有名為set_data的成員函數(shù),而這兩個(gè)成員函數(shù) 必須 使用 不同的標(biāo)號(hào)。參數(shù)之所以被編碼進(jìn)去是為了類(lèi)能通過(guò)攜帶其它參數(shù)來(lái)重載 成員函數(shù)set_data,正如標(biāo)準(zhǔn)的C++函數(shù)。但是,和以前一樣,不同的編 譯器在改編標(biāo)號(hào)時(shí)編碼信息的方式也不同。
下面的第2和第3行,出現(xiàn)了熟悉的函數(shù)的開(kāi)始部分。在第5行,把堆棧 中的第一個(gè)參數(shù)儲(chǔ)存到EAX中了。這并 不是參數(shù)x!替代它的是那個(gè)隱藏的參數(shù),它是指向此函數(shù)能起作用的對(duì)象的指針。第6行將參數(shù)x儲(chǔ)存 到EDX中了,而第7行又將EDX儲(chǔ)存到了EAX指向的雙字中。它是Simple對(duì)象 中的data成員,也是這個(gè)類(lèi)中的唯一的數(shù)據(jù),它儲(chǔ)存在Simple結(jié)構(gòu)體中偏 移地址為0的地方。
這一節(jié)使用了這章中的思想創(chuàng)建了一個(gè)C++類(lèi):用來(lái)描述任意大小的 無(wú)符號(hào)整形。因?yàn)橐枋鋈我獯笮〉恼?,所以它需要?chǔ)存到一個(gè)無(wú)符號(hào)整形的數(shù)組(雙字的)中。可以使用動(dòng)態(tài)分配來(lái)實(shí)現(xiàn)任意大小的整形。雙 字是以相反的方向儲(chǔ)存的 ( 也就是說(shuō) ,雙字的最低有效位的下標(biāo)為0)。 圖 7.16展示了Big_int類(lèi)的定義。Big_int的大小是通過(guò)測(cè)量unsigned數(shù) 組的大小得到的,用來(lái)儲(chǔ)存它的數(shù)據(jù)。此類(lèi)中的size 數(shù)據(jù)成員的偏移地址 為0,而number_成員的偏移為4。
圖 7.16: Big_int類(lèi)的定義
為了簡(jiǎn)單化這些例子,只有擁有大小相同的數(shù)組的對(duì)象實(shí)例才可以相互 進(jìn)行加減操作。 這個(gè)類(lèi)有三個(gè)構(gòu)造函數(shù)(constructor):第一個(gè)構(gòu)造函數(shù)(第9行)使用了一 個(gè)正常的無(wú)符號(hào)整形來(lái)初始化類(lèi)實(shí)例;第二個(gè)構(gòu)造函數(shù)(第18行)使用了一個(gè) 包含一個(gè)十六進(jìn)制值的字符串來(lái)初始化類(lèi)實(shí)例。第三個(gè)構(gòu)造函數(shù)(第21行)是拷貝構(gòu)造函數(shù) (copy constructor)。
因?yàn)檫@里使用的是匯編語(yǔ)言,所以討論的焦點(diǎn)在于加法和減法運(yùn)算符如何工作。圖 7.17展示了與這些運(yùn)算符相關(guān)的部分頭文件。它們展示了如何創(chuàng)建運(yùn)算符來(lái)調(diào)用匯編程序。因?yàn)椴煌木幾g器使用完全不同的名字改編 規(guī)則來(lái)改編運(yùn)算符函數(shù),所以創(chuàng)建了內(nèi)聯(lián)的運(yùn)算符函數(shù)來(lái)調(diào)用C鏈接匯編程序。這就使得在不同編譯器間的移植變得相對(duì)容易些,而且和直接調(diào)用速 度一樣快。這項(xiàng)技術(shù)同樣免去了從匯編中拋出異常的必要!
為什么在這里使用的全部是匯編語(yǔ)言呢?回想一下,在執(zhí)行多倍精 度運(yùn)算時(shí),進(jìn)位必須從一個(gè)雙字移去與下一個(gè)有效的雙字進(jìn)行加法操作。C++(和C)并不允許程序員訪(fǎng)問(wèn)CPU的進(jìn)位標(biāo)志位。只有通過(guò)讓C++獨(dú) 立地重新計(jì)算出進(jìn)位標(biāo)志位后有條件地與下一個(gè)雙字進(jìn)行加法操作,才能執(zhí)行這個(gè)加法操作。使用匯編語(yǔ)言來(lái)書(shū)寫(xiě)代碼會(huì)更有效,因?yàn)樗梢栽L(fǎng)問(wèn) 進(jìn)位標(biāo)志位,可以使用ADC指令來(lái)自動(dòng)將進(jìn)位標(biāo)志位加上,這樣做更有道 理。
為了簡(jiǎn)化,只有add_big_ints的匯編程序?qū)⒃谶@討論。下面是這個(gè)程序 的代碼(來(lái)自big_math.asm):
希望,到此刻為止讀者能明白大部分這里的代碼。第25行到27行將Big_int對(duì) 象傳遞的指針儲(chǔ)存到寄存器中。記住引用的僅僅是指針。第31行到35行檢查保證三個(gè)對(duì)象數(shù)組的大小是一樣的。(注意,size_的偏移被加到指針中了,為了訪(fǎng)問(wèn)數(shù)據(jù)成員。)第44行和第46行調(diào)整寄存器,讓它們指向被各自對(duì)象使用的數(shù)組,用來(lái)替代使用對(duì)象本身。(同樣,number_的偏移被加到 對(duì)象指針中了。)
在第52行到57行的循環(huán)中,將儲(chǔ)存在數(shù)組里的整形一起相加,首先加的是最低有效的雙字,然后是下一最低有效的雙字, 等等。 多倍精度運(yùn)算必須以這樣的順序來(lái)完成(看小節(jié) 2.1.5)。第59行用來(lái)檢查溢出,一旦溢出, 進(jìn)位標(biāo)志位將由最后進(jìn)行加法運(yùn)算的最高有效位置位。因?yàn)閿?shù)組里的雙字 是以little endian順序儲(chǔ)存的,所以循環(huán)從數(shù)組的開(kāi)始處開(kāi)始,依次向前直到結(jié)束。
圖 7.18展示了Big_int的簡(jiǎn)單應(yīng)用的簡(jiǎn)短的例子。注意,Big_int常量必 須明確聲明,如第16行。這有兩個(gè)原因。首先,沒(méi)有轉(zhuǎn)換構(gòu)造函數(shù)來(lái)將一個(gè)無(wú)符號(hào)整形轉(zhuǎn)換成Big_int類(lèi)型。其次,只有相同大小的Big _int數(shù)才能 用來(lái)進(jìn)行相加操作。這里進(jìn)行類(lèi)型轉(zhuǎn)換是有問(wèn)題的,因?yàn)橐佬柁D(zhuǎn)換的大小是非常困難的。此類(lèi)的一個(gè)更高級(jí)的實(shí)現(xiàn)將允許任意大小的數(shù)之間的相加。作者不打算因?yàn)橐獙?shí)現(xiàn)任意大小的數(shù)的相加而把這個(gè)例子弄得過(guò)度復(fù)雜。(但是,鼓勵(lì)讀者來(lái)實(shí)現(xiàn)它。)
更多建議: