免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
effective C++ 導(dǎo)讀

導(dǎo)讀

學(xué)會(huì)一個(gè)程式語(yǔ)言,是一回事兒;學(xué)會(huì)如何以此語(yǔ)言設(shè)計(jì)並實(shí)作出有效的程式,又是一回事兒。C++ 尤其如此,因?yàn)樗懿粚こ5睾w了罕見(jiàn)的威力和豐富的表現(xiàn)力,不但建立在一個(gè)全功能的傳統(tǒng)語(yǔ)言(C)之上,更提供極為廣泛的物件導(dǎo)向(object-oriented)性質(zhì),以及對(duì)templates 和exceptions(異常狀態(tài))的支援。

假以適當(dāng)運(yùn)用,C++ 是個(gè)可以讓你感受愉悅的夥伴。各種不同的設(shè)計(jì)方式,包括物件導(dǎo)向型式和傳統(tǒng)型式,都可以直接在這個(gè)語(yǔ)言中表現(xiàn)並有效地實(shí)作出來(lái)。你可以定義新的資料型別,它們和語(yǔ)言內(nèi)建的型別表面上無(wú)分軒輊,實(shí)質(zhì)上則更具彈性。明智地選用一些謹(jǐn)慎設(shè)計(jì)的classes — 自動(dòng)完成記憶體管理、別名(aliasing)處理、初始化動(dòng)作與清理動(dòng)作、型別轉(zhuǎn)換、以及軟體開(kāi)發(fā)的其他難題與禍根— 可以使程式設(shè)計(jì)更容易,更直觀,更有效,更少錯(cuò)誤。是的,要寫(xiě)出有效的C++ 程式並不會(huì)太困難,如果你知道怎麼做的話。

如果沒(méi)有什麼訓(xùn)練與素養(yǎng),就冒然使用C++,會(huì)導(dǎo)至做出來(lái)的碼不易理解、不易維護(hù)、不易擴(kuò)充、缺乏效率、而且容易出錯(cuò)。

關(guān)鍵在於找出C++ 可能絆倒你的狀況有哪些,然後學(xué)習(xí)如何避開(kāi)它們。這正是本書(shū)的目的。我假設(shè)你已經(jīng)認(rèn)識(shí)C++ 並對(duì)它有某種程度的使用經(jīng)驗(yàn)。我提供一些準(zhǔn)則,讓你更有效地使用這個(gè)語(yǔ)言,使你的軟體容易理解、容易維護(hù)、容易擴(kuò)充、效率高、而且行為如所預(yù)期。

我提出的忠告分為兩大類:一般性的設(shè)計(jì)策略,以及特殊的(比較難得一見(jiàn)的)語(yǔ)言性質(zhì)。

設(shè)計(jì)方面的討論集中在如何對(duì)不同的方法(俾得以C++ 達(dá)成某個(gè)目標(biāo))做取捨。如何在inheritance(繼承)和templates(範(fàn)本)之間做選擇?在templates 和generic pointers(泛型指標(biāo))之間?在public inheritance(公開(kāi)繼承)和private inheritance (私有繼承)之間?在private inheritance 和layering(分層技術(shù))之間?在function overloading(函式多載化)和parameter defaulting(參數(shù)預(yù)設(shè)值)之間?在virtual function(虛擬函式)和nonvirtual functions(非虛擬函式)之間?在pass-by-value (傳值)和pass-by-reference(傳址)之間?一開(kāi)始就做出正確的決定是很重要的,因?yàn)椴徽_的選擇或許不會(huì)一下子就浮現(xiàn)影響,但是在開(kāi)發(fā)過(guò)程的後期,矯正它往往很困難、很花時(shí)間,很混亂,很令人沮喪,事倍功半,成本很高。

在你確切知道你要做什麼之後,把它做對(duì),恐怕也不是件太容易的事。什麼是 assignment 運(yùn)算子的適當(dāng)傳回型別?當(dāng)operator new 無(wú)法找出足夠的記憶體,它該有怎樣的行為?destructor 何時(shí)應(yīng)該被宣告為virtual?你應(yīng)該寫(xiě)一個(gè)member initialization list(成員初值列)嗎?在如斯細(xì)節(jié)中努力,也頗具有決定性,因?yàn)槿绻贿@樣,常會(huì)導(dǎo)至意料之外或神秘難解的程式行為。更糟的是這類脫軌行為可能不會(huì)立即浮現(xiàn),這些恐怖的碼或能通過(guò)品管檢驗(yàn),卻仍然藏匿著許多未偵測(cè)出來(lái)的臭蟲(chóng)— 不定時(shí)炸彈正等待引爆。

這不是本得一頁(yè)頁(yè)讀下去才有感覺(jué)的書(shū)籍。你甚至不需要依序讀它。所有素材被我分為50 個(gè)條款,每一個(gè)都相當(dāng)獨(dú)立。不過(guò)條款之間會(huì)彼此參考,所以閱讀本書(shū)的一種方法是先從感興趣的條款開(kāi)始,然後遵循其參考指示,進(jìn)一步讀下去。

所有條款被我分為七大類。如果你對(duì)某類主題特別感興趣,例如「記憶體管理」或「物件導(dǎo)向設(shè)計(jì)」,可以從相關(guān)章節(jié)開(kāi)始,一路讀下去,或是跳躍前進(jìn)。不過(guò)最後你會(huì)發(fā)現(xiàn),本書(shū)的所有內(nèi)容對(duì)於高實(shí)效的C++ 程式設(shè)計(jì)而言,都十分基礎(chǔ)而重要,所以幾乎每個(gè)條款最後都會(huì)和其他條款互有牽連。

這並不是一本C++ 參考工具書(shū),也不是一本讓你從頭學(xué)習(xí)C++ 的書(shū)。例如,雖然我熱切告訴你一些有關(guān)「撰寫(xiě)自己的operator new」的注意事項(xiàng)(條款7~10),但是我假設(shè)你可以從其他地方獲知,operator new 必須傳回一個(gè)void*,其第一引數(shù)的型別必須是size_t。許多C++ 語(yǔ)言書(shū)可以帶給你這樣的資訊。

這本書(shū)的目的是要強(qiáng)調(diào)那些其他書(shū)籍往往淺淺帶過(guò)(如果有的話)的C++ 程式設(shè)計(jì)概念。其他書(shū)籍描述的是C++ 語(yǔ)言的各個(gè)成份,本書(shū)則告訴你如何將那些成份組合起來(lái),完成一個(gè)有效的程式。其他書(shū)籍告訴你如何讓程式順利編譯,本書(shū)則告訴你如何避開(kāi)編譯器不會(huì)告訴你的一些問(wèn)題。

和大部份語(yǔ)言一樣,C++ 有著豐富的「?jìng)鹘y(tǒng)」,在程式員之間口耳相傳,形成這個(gè)語(yǔ)言的偉大傳承的一部份。我企圖在這本書(shū)中以容易閱讀的型式記錄一些長(zhǎng)久累積而來(lái)的智慧。

然而在此同時(shí),我必須告訴你,本書(shū)僅限於正統(tǒng)的、可移植的C++ 語(yǔ)言。只有明列於ISO/ANSI 標(biāo)準(zhǔn)(見(jiàn)條款M35)中的性質(zhì),才會(huì)被本書(shū)採(cǎi)用。本書(shū)之中,移植性是個(gè)關(guān)鍵考量。如果你想要尋找因編譯器而異的特殊技法,本書(shū)不適合你。

但是,啊呀,標(biāo)準(zhǔn)規(guī)格所描述的C++,與社區(qū)軟體商店所賣的編譯器(s) 的表現(xiàn),多少有點(diǎn)出入。所以當(dāng)我指出某個(gè)新的語(yǔ)言特性頗有用處時(shí),我也會(huì)告訴你如何在缺乏那些特性的情況下產(chǎn)出有效的軟體。畢竟在確知未來(lái)即將如何如何之際,卻忽略那些美麗遠(yuǎn)景而儘做些低下的勞力工作,容我坦言是相當(dāng)愚蠢的;但是反過(guò)來(lái)看,你也不能在最新最偉大的C++ 編譯器(s) 降臨世界之前,空自等待而束手無(wú)策呀。你必須和你手上可用的工具一起打拼,而本書(shū)正打算幫助你這麼做。

注意我說(shuō)編譯器(s) — 複數(shù)。不同的編譯器對(duì)標(biāo)準(zhǔn)C++ 的滿足程度各不相同,所以我鼓勵(lì)你至少以兩種編譯器(s) 來(lái)開(kāi)發(fā)程式。這麼做可以幫助你避免不經(jīng)意仰賴某個(gè)編譯器專屬的語(yǔ)言延伸性質(zhì),或是誤用某個(gè)編譯器對(duì)標(biāo)準(zhǔn)規(guī)格的錯(cuò)誤闡示。這也可以幫助你避免使用過(guò)度先進(jìn)的編譯器特殊技術(shù),例如獨(dú)家廠商才做得出來(lái)的某種語(yǔ)言新特性。如此特性往往實(shí)作不夠精良(臭蟲(chóng)多,要不就是表現(xiàn)遲緩,或兩者兼具),而且C++ 社群往往對(duì)這些特性缺乏使用經(jīng)驗(yàn),無(wú)法給你應(yīng)用上的忠告。雷霆萬(wàn)鈞之勢(shì)固然令人興奮,但當(dāng)你的目標(biāo)是要產(chǎn)出可靠的碼,恐怕還是步步為營(yíng)(並且能夠與人合作)得好。

你在本書(shū)中找不到C++ 的必殺秘笈,也看不到通往C++ 完美軟體的唯一真理。 50 個(gè)條款中的每一個(gè)帶給你的都只是準(zhǔn)則,包括如何完成較好的設(shè)計(jì),如何避免常見(jiàn)的問(wèn)題,如何到達(dá)更好的效率,但任何條款都不可能放之四海皆準(zhǔn)。軟體的定義和實(shí)作是極為複雜的工作,常會(huì)受到硬體、作業(yè)系統(tǒng)、以及應(yīng)用軟體的束縛,所以我能夠做的最好事情就是提供一些準(zhǔn)則,讓你可以依循產(chǎn)生出比較好的程式。

如果任何時(shí)候你都奉行每一個(gè)條款,應(yīng)該不太可能掉進(jìn)最常見(jiàn)的一些C++ 陷阱。不過(guò)準(zhǔn)則畢竟只是準(zhǔn)則,可能存在例外情況。那正是為什麼每個(gè)條款都帶有一堆解釋的原因。這些解釋是本書(shū)最重要的資產(chǎn)。唯有徹底瞭解一個(gè)條款背後的基本原理,你才能合理決定此條款是否適用於手上的專案,或你正艱苦奮鬥的難題上。

本書(shū)的最佳用途,就是增進(jìn)你對(duì)C++ 行為的瞭解,知道它為什麼有那樣的表現(xiàn),以及如何將其行為轉(zhuǎn)化為你的利益。盲目運(yùn)用本書(shū)所列的條款並不適當(dāng),不過(guò)話說(shuō)回來(lái),你或許不應(yīng)該在缺乏好理由的情況任意違反任何一個(gè)條款。

這樣性質(zhì)的書(shū)籍中,專用術(shù)語(yǔ)的解釋並非重點(diǎn)所在。那樣的工作頂好是留給語(yǔ)言界的「律師」去做。然而有少量C++ 辭彙是每個(gè)人都應(yīng)該要懂的。以下術(shù)語(yǔ)一再出現(xiàn),所以有必要確定你我之間對(duì)它們有共同的認(rèn)知。

所謂宣告(declaration),用來(lái)將一個(gè)object、function、class 或template 的型別名稱告訴編譯器。宣告式並不帶有細(xì)目資訊。下面統(tǒng)統(tǒng)都是宣告:

extern int x; // object declaration
int numDigits(int number); // function declaration
class Clock; // class declaration
template
class SmartPointer; // template declaration

所謂定義(definition),用來(lái)將細(xì)目資訊提供給編譯器。對(duì)object 而言,其定義式是編譯器為它配置記憶體的地點(diǎn)。對(duì)function 或function template 而言,其定義式提供函式本體(function body)。對(duì)class 或class template 而言,其定義式必須列出該class 或template 的所有members:

int x; // 這是物件的定義式int numDigits(int number) // 這是函式的定義式{ // 此函式傳回其參數(shù)的數(shù)位(digits)個(gè)數(shù)int digitsSoFar = 1;if (number < 0) {number = -number;++digitsSoFar;}while (number /= 10) ++digitsSoFar;return digitsSoFar;}class Clock { // 這是class 的定義式public:Clock();~Clock();int hour() const;int minute() const;int second() const;...};templateclass SmartPointer { // 這是template 的定義式public:SmartPointer(T *p = 0);~SmartPointer();T * operator->() const;T& operator*() const;...};
上述程式碼把我們帶往所謂的constructors。default constructor 意指可以「不需任何引數(shù)就被喚起」者。這樣的一個(gè)constructor 如果不是沒(méi)有任何參數(shù),就是每個(gè)參數(shù)都有預(yù)設(shè)值。通常當(dāng)你需要定義物件陣列時(shí),就會(huì)需要一個(gè)default constructor

class A {public:A(); // default constructor};A arrayA[10]; // 呼叫constructors 10 次class B {public:B(int x = 0); // default constructor};B arrayB[10]; // 呼叫constructors 10 次,// 每次都給引數(shù)0。class C {public:C(int x); // 這不是一個(gè)default constructor};C arrayC[10]; // 錯(cuò)誤!

或許有時(shí)候你會(huì)發(fā)現(xiàn),某個(gè)class 的default constructor 有預(yù)設(shè)參數(shù)值,你的編譯器卻拒不接受其物件陣列。例如某些編譯器拒絕接受上述arrayB 的定義,即使它其實(shí)符合C++ 標(biāo)準(zhǔn)。這是存在於C++ 標(biāo)準(zhǔn)規(guī)格書(shū)和實(shí)際編譯器行為之間的一個(gè)矛盾例子。截至目前我所知道的每一個(gè)編譯器,都有一些這類不相容缺點(diǎn)。在編譯器廠商追上C++ 語(yǔ)言標(biāo)準(zhǔn)之前,請(qǐng)保持你的彈性,並安慰自己,也許不久後的某一天,C++ 編譯器的表現(xiàn)就可以和C++ 標(biāo)準(zhǔn)規(guī)格書(shū)所描述的一致了。

附帶一提,如果你想要產(chǎn)生一個(gè)物件陣列,但該物件型別沒(méi)有提供default constructor,通常的作法是定義一個(gè)指標(biāo)陣列取而代之,然後利用new 一一將每個(gè)指標(biāo)初始化:

C *ptrArray[10]; // 沒(méi)有呼叫任何constructorsptrArray[0] = new C(22); // 配置並建構(gòu)一個(gè)C 物件ptrArray[1] = new C(4); // 同上...

這個(gè)作法在任何場(chǎng)合幾乎都?jí)蛴昧?。如果不夠,你或許得使用條款14 所說(shuō)的更高層次(也因此更不為人知)的"placement new" 方法?;氐叫g(shù)語(yǔ)來(lái)。所謂copy constructor 係以某物件做為另一同型物件的初值:

class String {public:String(); // default constructorString(const String& rhs); // copy constructor...private:char *data;};String s1; // 呼叫default constructorString s2(s1); // 呼叫copy constructorString s3 = s2; // 呼叫copy constructor

或許copy constructor 最重要的用途就是用來(lái)定義何謂「以by value 方式傳遞和傳回物件」。例如,考慮以下效率不佳的作法,以一個(gè)函式串接兩個(gè)String 物件:

const String operator+(String s1, String s2){String temp;delete [] temp.data;temp.data =new char[strlen(s1.data) + strlen(s2.data) + 1];strcpy(temp.data, s1.data);strcat(temp.data, s2.data);return temp;}String a("Hello");String b(" world");String c = a + b; // c = String("Hello world")

其中operator+ 需要兩個(gè)String 物件做為參數(shù),並傳回一個(gè)String 物件做為運(yùn)算結(jié)果。不論參數(shù)或運(yùn)算結(jié)果都是以by value 方式傳遞,所以在operator+進(jìn)行過(guò)程中,會(huì)有一個(gè)copy constructor 被喚起,用以將a 當(dāng)做s1 的初值,再有一個(gè)copy constructor 被喚起,用以將b 當(dāng)做s2 的初值,再有一個(gè)copyconstructor 被喚起,用以將temp 當(dāng)做c 的初值。事實(shí)上,只要編譯器決定產(chǎn)生中介的暫時(shí)性物件,就會(huì)需要一些copy constructor 呼叫動(dòng)作(見(jiàn)條款M19)。重點(diǎn)是:pass-by-value 便是「呼叫copy constructor」的同義詞。

順帶一提,你不能夠真的像上述那樣實(shí)作Strings 的operator+。傳回一個(gè)const String object 是正確的(見(jiàn)條款2123),但是你應(yīng)該以by reference 方式(見(jiàn)條款22)傳遞那兩個(gè)參數(shù)

其實(shí),如果你有外援,並不需要為Strings 撰寫(xiě)operator+。事實(shí)上你的確有外援,因?yàn)镃++ 標(biāo)準(zhǔn)程式庫(kù)(條款49)就內(nèi)含有一個(gè)string 型別,帶有一個(gè) operator+,做的事情幾乎就是上述operator+ 的行為。本書(shū)中我並用String 和string 兩者(注意前者名稱以大寫(xiě)開(kāi)頭,後者否),但方式不同。如果我只是需要一般字串,不在意它是怎麼做出來(lái)的,那麼我便使用標(biāo)準(zhǔn)程式庫(kù)提供的 string。這也是你應(yīng)該選擇的行為。然而如果我打算剖析C++ 的行為,並因而需要某些實(shí)作碼來(lái)示範(fàn)或驗(yàn)證,我便使用非標(biāo)準(zhǔn)的那個(gè)String class。身為一個(gè)程式員,只要必須用到字串,就應(yīng)該儘可能使用標(biāo)準(zhǔn)的string 型別;那種「開(kāi)發(fā)自己的字串類別,以象徵具備C++ 某種成熟功力」的日子已經(jīng)過(guò)去了(不過(guò)你還是有必要瞭解開(kāi)發(fā)一個(gè)像string 那樣的classes 所需知道的課題)。對(duì)「示範(fàn)或驗(yàn)證」目的(而且可說(shuō)只對(duì)此種目的)而言,String 很是方便。無(wú)論如何,除非你有很好的理由,否則都不應(yīng)該再使用舊式的char*-based 字串。具有良好定義的string 型別如今已能夠在每一方面比char*s 更具優(yōu)勢(shì),並且更好— 包括其執(zhí)行效率(見(jiàn)條款49和條款M29~M30)。

接下來(lái)兩個(gè)需要掌握的術(shù)語(yǔ)是initialization(初始化)和assignment(指派)。物件的初始化行為發(fā)生在它初次獲得一個(gè)值的時(shí)候。對(duì)於「帶有constructors」之 classes 或structs,初始化總是經(jīng)由喚起某個(gè)constructor 達(dá)成。這和物件的 assignment 動(dòng)作不同,後者發(fā)生於「已初始化之物件被指派新值」的時(shí)候:

string s1; // initialization(初始化)string s2("Hello"); // initialization(初始化)string s3 = s2; // initialization(初始化)s1 = s3; // assignment(指派)

純粹從操作觀點(diǎn)看,initializationassignment 之間的差異在於前者由constructor 執(zhí)行,後者由operator= 執(zhí)行。換句話說(shuō)這兩個(gè)動(dòng)作對(duì)應(yīng)不同的函式動(dòng)作。

C++ 嚴(yán)格區(qū)分此二者,原因是上述兩個(gè)函式所考慮的事情不同。Constructors 通常必須檢驗(yàn)其引數(shù)的有效性(validity),而大部份assignment 運(yùn)算子不必如此,因?yàn)槠湟龜?shù)必然是合法的(因?yàn)橐驯唤?gòu)完成)。另一方面,assignment 動(dòng)作的目標(biāo)物件並非是尚未建構(gòu)完成的物件,而是可能已經(jīng)擁有配置得來(lái)的資源。在新資源可被指派過(guò)去之前,舊資源通常必須先行釋放。這裡所謂的資源通常是指記憶體。在assignment 運(yùn)算子為一個(gè)新值配置記憶體之前,必須先釋放舊值的記憶體。
下面是String 的constructorassignment 運(yùn)算子的可能作法:

// 以下是一個(gè)可能的String constructorString::String(const char *value) {{if (value) { // 如果指標(biāo)value 不是nulldata = new char[strlen(value) + 1];strcpy(data,value);}else { // 處理null 指標(biāo)    //此一「接受一個(gè)const char* 引數(shù)」的String constructor,    //有能力處理傳進(jìn)來(lái)的指標(biāo)為null的情況。標(biāo)準(zhǔn)的string 可沒(méi)如此寬容?!  ?//企圖以一個(gè)null 指標(biāo)產(chǎn)生一個(gè)string,其結(jié)果未有定義。    //不過(guò)以一個(gè)空的char*-based 字串(例如"")產(chǎn)生一個(gè)string 物件,    //倒是安全的。data = new char[1];}}// 以下是一個(gè)可能的String assignment 運(yùn)算子String& String::operator=(const String& rhs){if (this == &rhs)return *this; // 見(jiàn)條款17delete [] data; // 刪除(釋放)舊有的記憶體data = // 配置新的記憶體new char[strlen(rhs.data) + 1];strcpy(data, rhs.data);return *this; // 見(jiàn)條款15}

注意,constructor 必須檢驗(yàn)其參數(shù)的有效性,並確保member data 都被適當(dāng)?shù)爻跏蓟?/font>,例如一個(gè)char* 指標(biāo)必須被適當(dāng)?shù)丶由蟦ull 結(jié)束字元。亦請(qǐng)注意 assignment 運(yùn)算子認(rèn)定其參數(shù)是合法的,反倒是它會(huì)偵測(cè)諸如「自己指派給自己」這樣的病態(tài)情況(見(jiàn)條款17),或是集中心力確?!概渲眯掠洃涹w之前先釋放舊有記憶體」。這兩個(gè)函式的差異,象徵物件初始化(initialization)和物件指派(assignment)兩者的差異。順帶一提,如果delete [] 這樣的表示法對(duì)你而言很陌生,條款5 和條款M8 應(yīng)該能夠消除你的任何相關(guān)疑惑。

我要討論的最後一個(gè)術(shù)語(yǔ)是client(客戶)。Client 代表任何「使用你所寫(xiě)的碼」的人。當(dāng)我在本書(shū)提及clients,我指的便是任何觀察你的碼並企圖理解它們的人。我也是指閱讀你的class 定義並企圖決定是否可以繼承它們的人。我同時(shí)也是指那些審查你的設(shè)計(jì)並希望洞察其中原理的人。你或許還不習(xí)慣去想到你的clients,但是我會(huì)儘量說(shuō)服你設(shè)法讓他們的生活愉快一些。畢竟,你也是他人所開(kāi)發(fā)的軟體的client,難道你不希望那些人讓你的生活愉快一些嗎?此外,也許有一天你會(huì)發(fā)現(xiàn)你必須使用自己所寫(xiě)的碼(譯註:指那些classes 或libraries),那時(shí)候你的client 就是你自己。

我在本書(shū)用了兩個(gè)你可能不甚熟悉的C++ 性質(zhì),它們都是晚近才加入C++ 標(biāo)準(zhǔn)之中。第一個(gè)是bool 型別,其值若非true 就是false(兩者都是關(guān)鍵字)。語(yǔ)言內(nèi)建的相對(duì)關(guān)係運(yùn)算子(如<, >, ==)的傳回型別都是bool,if, for, while, do 等述句的條件判斷式的傳回型別也是bool。如果你的編譯器尚未實(shí)作出bool 型別,你可以利用typedef 模擬bool,再以兩個(gè)const 物件模擬true 和false:

typedef int bool;const bool false = 0;const bool true = 1;

這種手法相容於傳統(tǒng)的C/C++ 語(yǔ)意。使用這種模擬作法的程式,在移植到一個(gè)支援bool 型別的編譯器平臺(tái)後,行為並不會(huì)改變。如果你想知道另一種bool 模擬法,包括其優(yōu)缺點(diǎn)討論,請(qǐng)參考More Effective C++ 的導(dǎo)讀部份。

第二個(gè)新特性其實(shí)有四樣?xùn)|西,分別是static_cast, const_cast, dynamic_cast, reinterpret_cast 四個(gè)轉(zhuǎn)型運(yùn)算子。傳統(tǒng)的C 轉(zhuǎn)型動(dòng)作如下:

(type) expression // 將expression 轉(zhuǎn)為type 型別

新的轉(zhuǎn)型動(dòng)作則是這樣:

static_cast(expression) // 將expression 轉(zhuǎn)為type 型別const_cast(expression)dynamic_cast(expression)reinterpret_cast(expression)

這些不同的轉(zhuǎn)型運(yùn)算子有不同的作用:

const_cast用來(lái)將物件或指標(biāo)的常數(shù)性(constness)轉(zhuǎn)型掉,我將在條款21驗(yàn)證這個(gè)主題。
dynamic_cast用來(lái)執(zhí)行「安全的向下轉(zhuǎn)型動(dòng)作(safe downcasting)」,這是條款39 的主題。
reinterpret_cast的轉(zhuǎn)型結(jié)果取決於編譯器— 例如在函式指標(biāo)型別之間做轉(zhuǎn)型動(dòng)作。你大概不常需要用到reinterpret_cast。本書(shū)完全沒(méi)有用到它。
static_cast是個(gè)「雜物袋」:沒(méi)有其他適當(dāng)?shù)霓D(zhuǎn)型運(yùn)算子可用時(shí),就用這個(gè)。它最接近傳統(tǒng)的C 轉(zhuǎn)型動(dòng)作。

傳統(tǒng)的C 轉(zhuǎn)型動(dòng)作仍然合法,但是新的轉(zhuǎn)型運(yùn)算子比較受歡迎。它們更容易在程式碼中被識(shí)別出來(lái)(不論是對(duì)人類或是對(duì)諸如grep 等工具而言),而且愈是縮小範(fàn)圍地指定各種轉(zhuǎn)型運(yùn)算子的目標(biāo),編譯器愈有可能診斷出錯(cuò)誤的運(yùn)用。例如,只有const_cast 才可以用來(lái)將某物的常數(shù)性(constness)轉(zhuǎn)換掉。如果你嘗試使用其他轉(zhuǎn)型運(yùn)算子來(lái)轉(zhuǎn)換物件或指標(biāo)的常數(shù)性,一定會(huì)踢到鐵板。

欲知這些新式轉(zhuǎn)型動(dòng)作的更多資訊,請(qǐng)看條款M2,或查閱較新的C++ 語(yǔ)言書(shū)籍。 M 代表More Effective C++,是我的另一本書(shū)。本書(shū)最後附有一份該書(shū)摘要。

本書(shū)的程式範(fàn)例中,我設(shè)法為objects, classes, functions 取一些有意義的名稱。許多書(shū)籍在選用識(shí)別名稱時(shí),都喜歡恪守一句箴言:簡(jiǎn)短是智慧的靈魂,但是我不,我喜歡一切都交待得清清楚楚。我努力打破傳統(tǒng),堅(jiān)不使用那種隱秘而不易為人識(shí)破天機(jī)的名稱。但偶爾我會(huì)被誘惑所屈服,使用兩個(gè)我最歡迎的參數(shù)名稱。其意義可能並不淺顯易懂,特別是如果你從未在任何編譯器開(kāi)發(fā)團(tuán)隊(duì)待過(guò)的話。

這兩個(gè)參數(shù)名稱是lhs 和rhs,分別意味"left-hand side"(左端)和"right-hand side"(右端)。我以它們做為二元運(yùn)算子各函式的參數(shù)名稱,尤其是operator== 和算術(shù)運(yùn)算子如operator*。舉個(gè)例子,如果a 和b 代表兩個(gè)分?jǐn)?shù)(rational numbers)物件,而如果分?jǐn)?shù)可經(jīng)由一個(gè)non-member function operator* 相乘,那麼算式:

a * b

等於這款形式的函式呼叫:

operator*(a, b)

我將宣告operator* 如下(一如你在條款23所見(jiàn)):

const Rational operator*(const Rational& lhs,const Rational& rhs);

如你所見(jiàn),左運(yùn)算元a 成為函式中的lhs,右運(yùn)算元b 成為函式中的rhs。

我也利用縮寫(xiě)字來(lái)為指標(biāo)命名,規(guī)則如下:「指向型別T 之物件」的指標(biāo),我稱為pt,意思是"pointer to T"。下面是幾則例子:

string *ps; // ps = ptr to stringclass Airplane;Airplane *pa; // pa = ptr to Airplaneclass BankAccount;BankAccount *pba; // pba = ptr to BankAccount

對(duì)於references,我亦採(cǎi)用類似習(xí)慣。也就是說(shuō),rs 大約就是一個(gè)reference-tostring, ra 則可能是一個(gè)reference-to-Airplane。

當(dāng)我談到member functions,偶而我會(huì)使用mf 這個(gè)名稱。

為避免任何混淆,任何時(shí)候我在書(shū)中提到「C 程式設(shè)計(jì)」時(shí),我說(shuō)的是ISO/ANSI 版的C 語(yǔ)言,而不是舊式的、沒(méi)那麼strongly-typed(強(qiáng)型式)的古典C 語(yǔ)言。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服