青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Shuffy

不斷的學(xué)習(xí),不斷的思考,才能不斷的進(jìn)步.Let's do better together!
posts - 102, comments - 43, trackbacks - 0, articles - 19

[轉(zhuǎn)]http://m.shnenglu.com/tiandejian/archive/2007/04/27/ecpp_09.html
第9條:永遠(yuǎn)
不要在構(gòu)造或析構(gòu)的過程中調(diào)用虛函數(shù)

讓我們直切正題:在程序進(jìn)行構(gòu)造或析構(gòu)期間,你絕不能調(diào)用虛函數(shù),這是因為這樣的調(diào)用并不會按你所期望的執(zhí)行,即使能夠順利執(zhí)行,你也不會覺得十分 舒服。如果你曾經(jīng)是一個 Java C# 的程序員,并且在最近期望返回 C++ 的懷抱,那么請你格外的注意這一條,因為在這一問題上, C++ 與其他語言走的是完全不同的兩條路線。

假設(shè)有一個股票交易模擬系統(tǒng),你為它編寫了一個類的層次化結(jié)構(gòu),其中包括實現(xiàn)購買、拋售等功能的類。會計應(yīng)該能夠?qū)@類交易進(jìn)行檢查,這一點很重要,所以說每創(chuàng)建一次交易時,都應(yīng)該在日志中進(jìn)行一次恰當(dāng)?shù)挠涗洝O旅媸且粋€看似合理的解決方案:

class Transaction {                    // 所有交易的基類

public:

 Transaction();

 virtual void logTransaction() const = 0; // 作類型相關(guān)的錄

 ...

};

 

Transaction::Transaction()             // 基類構(gòu)造函數(shù)的實現(xiàn)

{

 ...

 logTransaction();                    // 最后,記錄這次交易

}

 

class BuyTransaction: public Transaction { // 派生類

public:

 virtual void logTransaction() const;   // 如何記錄本類型交易

 ...

};

 

class SellTransaction: public Transaction { // 派生類

public:

 virtual void logTransaction() const; // 如何記錄本類型交易

 ...

};

請考慮一下當(dāng)下邊的代碼得到運行時會發(fā)生什么:

BuyTransaction b;

很明顯的是此時 BuyTransaction 的構(gòu)造函數(shù)將被調(diào)用,但是,首先必須調(diào)用一個 Transaction[1] 的構(gòu)造函數(shù)。對于一個派生的對象,其基類那一部分會首先得到構(gòu)造,然后才是派生類的部分。 Transaction 的構(gòu)造函數(shù)中最后一行調(diào)用了虛函數(shù) logTransaction ,意外的事情就從這里發(fā)生了:此處調(diào)用的是 Translation 版本的 logTransaction 函數(shù),而不是 BuyTransaction 版本的——即使此處創(chuàng)建的對象是 BuyTransaction 類型的。在基類得到構(gòu)造的時候,虛函數(shù)永遠(yuǎn)也不會嘗試去匹配派生類。取而代之的是,對象仍然保持基類的行為。更隨意一點的說法是,在基類得到構(gòu)造的過程中,虛函數(shù)并不會轉(zhuǎn)換為派生類的版本。

這一行為看上去匪夷所思,但是這里有很充足的理由來解釋它。由于基類的構(gòu)造函數(shù)先于派生類運行,在基類構(gòu)造函數(shù)得到運行的時候,派生類的數(shù)據(jù)成員還沒有被初始化。如果虛函數(shù)在基類構(gòu)造函數(shù)向下匹配派生類時得到了調(diào)用,那么基類函數(shù)幾乎都將與局部數(shù)據(jù)成員有關(guān),但此時這些數(shù)據(jù)成員仍未得到初始化。你的程序?qū)霈F(xiàn)無盡的不可預(yù)知的行為,你也會在整夜受到瑣碎的調(diào)試工作的折磨。當(dāng)一個對象中有一些部分還沒有得到初始化的時候,此時進(jìn)行調(diào)用固然是危險的,所以 C++ 不允許你這樣做。

實際上,本段介紹的內(nèi)容比上文更為基礎(chǔ)。對于一個派生類的對象來說,在其基類的構(gòu)造函數(shù)得到運行的時候,這一對象的類型就是基類的。不僅僅虛函數(shù)會解析為基類的,而且 C++ 中使用運行時類型信息 的部分(比如 dynamic_cast (參見第 27 條)和 typeid )也會將這個對象的類型看作基類的。在我們的示例中,為了初始化 BuyTransaction 對象中的基類部分,需要調(diào)用 Transaction 的構(gòu)造函數(shù),此時這一對象是 Transaction 類型的。以上介紹的就是 C++ 如何一一處理該對象的 每一部分,這種處理方式是有意義的:這個對象的 BuyTransaction 部分尚未得到初始化,所以認(rèn)為它們不存在是最安全的處理方法。直到派生類的構(gòu)造函數(shù)開始執(zhí)行,這個派生類產(chǎn)生的對象才會成為該派生類的對象。

對于析構(gòu)過程可以應(yīng)用同樣的推理方式。當(dāng)一個派生類的析構(gòu)函數(shù)開始運行時,對象中派生類的那一部分?jǐn)?shù)據(jù)成員將可能出現(xiàn)未知的行為,所以 C++ 會認(rèn)為它們并不存在。當(dāng)基類的析構(gòu)函數(shù)被調(diào)用時,這個對象將成為一個基類對象, C++ 有的部分——包括虛函數(shù)、 dynamic_cast 等等——都會這樣對待該對象。

在上文的示例代碼中, Transaction 的構(gòu)造函數(shù)對一個虛函數(shù)進(jìn)行了一次直接調(diào)用,很顯然這樣做是違背本條中的指導(dǎo)方針的。這樣的違規(guī)實在太容易發(fā)現(xiàn)了,一些編譯器都會對其做出警告。(其他一些則不會。參見 53 條對編譯器警告信息的討論 )即使沒有警告,問題依舊一定會在運行之前變得很明顯,這是因為 Transaction 中的 logTransaction 函數(shù)是純虛函數(shù),除非它得到了定義(不像是真的,但確實是可行的,參見第 34 ),程序才有可能會得到連接,其他情況都會報錯:連接器無法找到 Transaction::logTransaction 所必需的具體實現(xiàn)。

查找構(gòu)造和析構(gòu)過程中對虛函數(shù)的調(diào)用并不總是一帆風(fēng)順的。如果 Transaction 擁有多個構(gòu)造函數(shù),它們所進(jìn)行的工作中有一部分是相同的,那么可以將這一相同的部分(既公共初始化代碼)連同對 logTransaction 的調(diào)用放入一個私有的非虛初始化函數(shù)中,這樣做可以避免代碼重復(fù),從軟件工程角度來講這似乎是一個很好的做法,我們將這一函數(shù)命名為 init

class Transaction {

public:

 Transaction()

 { init(); }                      // 調(diào)用非虛函數(shù) ...

 

 virtual void logTransaction() const = 0;

 ...

 

private:

 void init()

 {

    ...

    logTransaction();              // ... 而這里調(diào)用的卻是一個虛函數(shù)!

 }

};

這樣的代碼與上文中的版本使用的是同一理念,但是這樣做所帶來的危害更為隱蔽和嚴(yán)重,這是因為這樣的代碼會得到正常的編譯和連接而不會報錯。這種情況下,由于 logTransaction 是一個 Transaction 中的純虛函數(shù),大多數(shù)運行時系統(tǒng)將會在調(diào)用這個純虛函數(shù)時終止程序的運行(通常情況下會針對這一結(jié)果顯示出一個消息)。然而如果 logTransaction 是一個“正常的”虛函數(shù)(也就是說,不是純虛的),并且在 Transaction 中給出了一些實現(xiàn),這一版本將能夠得到調(diào)用,程序?qū)?#8220;愉快地一路小跑”下去,而在創(chuàng)建一個派生類對象時,則會調(diào)用錯誤的 logTransaction 版本,為什么會這樣呢?這個問題只能由你自己來解決了。避免這類問題的唯一途徑就是:在正在創(chuàng)建或銷毀的對象的構(gòu)造函數(shù)和析構(gòu)函數(shù)中,確保永遠(yuǎn)不要調(diào)用虛函數(shù),對于構(gòu)造函數(shù)和析構(gòu)函數(shù)所調(diào)用的所有函數(shù)都應(yīng)遵守這一約定。

那么,每當(dāng)一個 Transaction 層的對象被創(chuàng)建時,如何確保去調(diào)用正確的 logTransaction 版本呢?顯然地,在 Transaction 的構(gòu)造函數(shù)中調(diào)用一個虛函數(shù)是一個錯誤的做法。

為解決這一問題我們可以另辟蹊徑。方案之一就是:將 Transaction 中的 logTransaction 變?yōu)橐粋€非虛函數(shù),然后要求派生類的構(gòu)造函數(shù)把必要的日志記錄傳遞給 Transaction 的構(gòu)造函數(shù)。這個構(gòu)造函數(shù)對于非虛 logTransaction 的調(diào)用就是安全的。就像這樣:

class Transaction {

public:

 explicit Transaction(const std::string& logInfo);

 void logTransaction(const std::string& logInfo) const;

   // 現(xiàn)在 logTransaction 是非虛函數(shù)

 ...

};

 

Transaction::Transaction(const std::string& logInfo)

{

 ...

 logTransaction(logInfo);             // 現(xiàn)在調(diào)用的是一個非虛函數(shù)

}

 

class BuyTransaction: public Transaction {

public:

 BuyTransaction( parameters )

 : Transaction(createLogString( parameters ))

 { ... }                              // 將記錄傳遞給基類構(gòu)造函數(shù)

 

   ...

 

private:

 static std::string createLogString( parameters );

};

換句話說,由于在構(gòu)造過程中,你不能在基類部分調(diào)用派生部分時使用虛函數(shù),此時,作為一種補償,你可以讓派生類為基類的構(gòu)造函數(shù)傳遞一些必要的構(gòu)造信息。

請注意上述示例里 BuyTransaction 類中靜態(tài)函數(shù) createLogString 的使用。這里使用了一個輔助函數(shù)來創(chuàng)建一個值,然后將這個值傳遞給基類構(gòu)造函數(shù),通常情況下這樣做更為方便(而且更具備可讀性),這樣做不會出現(xiàn)在成員初始化表中為基類提供所需信息所帶來的曲折性。由于這個函數(shù)被聲明為靜態(tài)的,將不會出現(xiàn)偶然觸及到這個初生的 BuyTransaction 對象中的那些看似未初始化的數(shù)據(jù)成員的危險。這一點很重要,因為這些數(shù)據(jù)成員正處于一個未知的狀態(tài),這一事實便解釋了為什么在基類部分構(gòu)造或析構(gòu)期間調(diào)用虛函數(shù)將不會在第一時間匹配到派生類。

需要記住的

不要在構(gòu)造和析構(gòu)的過程中調(diào)用虛函數(shù),因為這樣的調(diào)用永遠(yuǎn)不會轉(zhuǎn)向當(dāng)前執(zhí)行的析構(gòu)函數(shù)或構(gòu)造函數(shù)更深層的派生類中執(zhí)行。



[1] 原文此處是 transcation ,這是英文的書寫習(xí)慣,將“交易”一詞直接用于文章中,而忽略代碼的大小寫問題 。下文 中的 TRansaction 是為了起到強調(diào)作用。譯文為了與代碼保持一致,統(tǒng)一采 用了 Transaction 。——譯注

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美中文在线观看国产| 久久精品人人做人人综合| 亚洲一级在线| 欧美激情一区在线观看| 国产中文一区二区| 亚洲综合第一页| 一本大道久久a久久综合婷婷| 久久深夜福利| 亚洲国产高清自拍| 男人的天堂成人在线| 欧美一区二区啪啪| 国产香蕉97碰碰久久人人| 亚欧成人精品| 香港成人在线视频| 国产视频一区在线观看一区免费| 亚洲综合另类| 亚洲综合视频1区| 亚洲人成网在线播放| 午夜精品福利视频| 国产日韩欧美日韩大片| 久久久xxx| 久久久久久久尹人综合网亚洲| 国产在线观看精品一区二区三区 | 国产在线视频不卡二| 欧美在线视频全部完| 午夜亚洲福利在线老司机| 国产一区二区三区观看| 另类专区欧美制服同性| 蜜臀va亚洲va欧美va天堂 | 亚洲免费在线视频一区 二区| 狠狠色综合色区| 久久婷婷国产麻豆91天堂| 久久国产精品99国产| 在线精品亚洲| 最新国产乱人伦偷精品免费网站| 欧美精品久久久久a| 亚洲视频在线观看三级| 亚洲影院在线观看| 狠狠狠色丁香婷婷综合激情| 欧美成人自拍| 欧美日韩色一区| 欧美影院视频| 欧美成人午夜剧场免费观看| 亚洲一区二区三区中文字幕在线| 小黄鸭精品aⅴ导航网站入口| 亚洲国产精品悠悠久久琪琪| 亚洲蜜桃精久久久久久久| 国产在线观看精品一区二区三区 | 亚洲欧美日韩中文播放| 1204国产成人精品视频| 一区二区高清在线| 国内久久视频| 一区二区三区欧美| 在线看片欧美| 亚洲自拍高清| 日韩亚洲欧美一区| 久久久久成人网| 国产精品你懂的| 麻豆久久婷婷| 国产精品高潮呻吟久久av黑人| 老牛嫩草一区二区三区日本| 欧美视频一二三区| 蜜臀av在线播放一区二区三区| 国产精品成人一区二区三区吃奶| 欧美jjzz| 国产欧美精品在线播放| 亚洲日本一区二区三区| 伊人成人网在线看| 午夜视频精品| 亚洲一区视频在线观看视频| 欧美成人午夜免费视在线看片| 久久精品二区三区| 欧美日韩岛国| 欧美激情一区二区三区在线视频 | 影音先锋亚洲一区| 亚洲欧美日韩另类| 中文欧美日韩| 欧美精品1区2区| 欧美国产一区在线| 一区免费视频| 久久激情一区| 久久久噜噜噜| 国内伊人久久久久久网站视频| 亚洲一区高清| 亚洲欧美日韩国产综合精品二区 | 一区二区福利| 欧美日韩ab片| 亚洲乱码国产乱码精品精| 亚洲经典三级| 女主播福利一区| 欧美国产日产韩国视频| 一区二区三区欧美在线| 欧美激情在线有限公司| 欧美顶级大胆免费视频| 伊人成人在线| 久久午夜激情| 欧美大片在线影院| 最新日韩在线| 欧美精品在线一区二区| 亚洲精选在线| 亚洲欧美在线一区| 性色av一区二区三区红粉影视| 玖玖精品视频| 中文日韩在线| 国产丝袜美腿一区二区三区| 久久综合999| 国产亚洲精品久久飘花| 亚洲一区二三| 亚洲久久成人| 欧美激情一二三区| 狠狠色丁香久久婷婷综合丁香| 亚洲直播在线一区| 亚洲人体影院| 欧美激情亚洲| 亚洲国产精品精华液网站| 久久噜噜噜精品国产亚洲综合 | 欧美成人国产一区二区| 欧美一区二区免费| 在线国产日韩| 在线亚洲国产精品网站| 激情91久久| 亚洲国产天堂久久综合网| 亚洲国产精品久久人人爱蜜臀| 久久久久久电影| 日韩视频一区二区三区在线播放免费观看 | 亚洲第一主播视频| …久久精品99久久香蕉国产| 欧美大片免费观看在线观看网站推荐| 亚洲福利视频一区二区| 亚洲一区二三| 欧美专区日韩专区| 亚洲第一区中文99精品| 老色批av在线精品| 韩日在线一区| 欧美人与禽猛交乱配| 久久久久久久久久久久久女国产乱| 久久久久久夜精品精品免费| 亚洲美女在线看| 久久亚洲精品中文字幕冲田杏梨 | 欧美激情视频在线播放| 一本色道久久加勒比88综合| 欧美激情在线播放| 中日韩高清电影网| 一本色道久久综合狠狠躁篇怎么玩| 亚洲国产欧美久久| 亚洲少妇诱惑| 性18欧美另类| 亚洲精品久久久久久久久久久久| 久久成人18免费观看| 99精品99| 亚洲黄色在线观看| 国产一区二区久久久| 久久久久久电影| 亚洲天堂第二页| 欧美日韩中文字幕在线| 91久久在线观看| 最新国产成人在线观看| 国产精品麻豆成人av电影艾秋 | 禁久久精品乱码| 性欧美video另类hd性玩具| 日韩一区二区精品葵司在线| 国产午夜久久| 亚洲国产精品小视频| 欧美日韩一二三四五区| 先锋影音久久| 欧美高清视频一区二区三区在线观看| 亚洲国产精品成人一区二区| 亚洲欧美一区二区三区极速播放 | 91久久香蕉国产日韩欧美9色| 在线一区视频| 久久久久久穴| 欧美日韩喷水| 欧美另类变人与禽xxxxx| 欧美va天堂| 性欧美1819sex性高清| 亚洲激情欧美激情| 欧美**人妖| 久久综合中文| 久久国产精品亚洲va麻豆| 亚洲欧美中文字幕| 亚洲一区在线直播| 亚洲在线免费| 欧美一区二区三区另类| 母乳一区在线观看| 亚洲开发第一视频在线播放| 国内精品久久久久久久影视蜜臀| 亚洲精品一区二区在线| 亚洲第一精品夜夜躁人人爽| 久久国产精彩视频| 99国内精品| 欧美日韩高清区| 在线视频日韩| 亚洲伊人久久综合| 欧美午夜剧场| 欧美寡妇偷汉性猛交| 国产精品黄视频| 先锋亚洲精品| 亚洲一区二区三区国产| 亚洲一区二区综合| 欧美资源在线观看|