• <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>

            OxFAN

            ::Just For Fun::

               :: 首頁 :: 聯系 :: 聚合  :: 管理
              3 Posts :: 1 Stories :: 1 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(4)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            2009年4月30日 #

            [轉自TopLanguages里的 一篇帖子,并非原譯文,《常見邏輯謬誤》譯文地址:http://www.yeeyan.com/articles/view/65452/28581]

            當你與別人討論,嘗試獲得答案或解釋時,你可能會遇到一些人犯上邏輯謬誤。這樣的討論是無意義的。你可能嘗試向對手要求證據或提供其他假設,令你獲得更好或更簡 單的解釋。如果都失敗,可以嘗試指出你討論對手的問題。你可辨認他的邏輯問題以免深究,以及可告知討論對手關於他的謬誤。以下是簡單介紹其中最常見的謬誤: 

            人身攻擊(ad hominem): 
            拉丁語「向著人」的意思。辯者用人身攻擊來攻擊對手,而不是在討論議題。當辯者不能用證據、事實或理由去維護他的立場,他可能透過標簽、稻草人、罵人、挑釁及憤 怒的人身攻擊方式來攻擊對手。 

            訴諸無知(appeal to ignorance / argumentum ex silentio): 
            以訴諸無知作為某些證據。(例如:我們沒有證據說神不存在,所以祂一定存在。又例如:由於我們沒有關於外星人的知識,這表示他們并不存在。)對某些東西的無知, 是與它的存在與否無關。 

            全知論據(argument from omniscience): 
            (例如:所有人都相信某些東西,每個人都知道的。) 
            辯者需要有全知能力以清楚每個人的信仰、懷疑或他們的知識。小心如「所有」、「每個人」、「每種東西」、「絕對」等詞語。 

            訴諸信心(appeal to faith): 
            (例如:如果你不相信,是不能清楚明白的。)如果辯者倚仗信心作為他論據的根基,那麼你在以後的討論所能得到的將不多。根據定義,「信心」是倚靠相信,并非靠邏 輯或證據支持。信心倚賴非理性的思想,并會產生不妥協。 

            訴諸傳統(appeal to tradition): 
            (類似主流思想謬誤)(例如:占星、宗教、奴隸)只因為人們以此為傳統,與它本身的存活能力無關。 

            訴諸權威(argument from authority / argumentum ad verecundiam): 
            以「專家」或權威的說話作論據的根基,而不是用邏輯或證據來支持該論據。(例如:某某教授相信創造科學。)只由於某個權威的聲稱,不足以代表他已令這聲稱正確。 假如辯者展示某專家的論據,那麼看看它有否伴隨著原因,以及它背後證據的來源。 

            不良後果論據(argument from adverse consequences): 
            (例如:我們應判被告有罪,否則其他人會仿效而犯上類似的罪行。)只因為討厭的罪行或行為出現,并不足以代表被告犯了該罪,或代表我們應判他有罪。(又例如:災 難的出現是因為神懲罰不信者,所以我們都應該信神。)只因災害或慘劇發生,與神是否存在、或我們該信甚麼并無關系。 

            恐嚇論據(argumentum ad baculum): 
            論據根基於恐懼或威脅。(例如:如果你不信神,你將會下地獄被火燒。) 

            無知論據(argumentum ad ignorantiam): 
            誤導性的論據,倚仗於人們的無知。 

            群眾論據(argumentum ad populum): 
            論據訴諸感性的弱點,而非事實和原因,旨在煽動群眾的支持。 

            主流思想謬誤(bandwagon fallacy): 
            只因為很多人相信或實踐,便認為一個思想有價值。(例如:大多數人相信神,所以它一定是真的。)只因為很多人相信某些東西,與那是事實與否并無關系。如很多人在 黑死病時期都相信疫癥是由於魔鬼引起,有多少人相信跟疫癥的起因全無關系。 

            竊取論點(begging the question): 
            (例如:我們必須鼓勵年青人去崇拜神,以灌輸道德行為。)可是宗教與崇拜真的產生道德行為嗎? 

            循環論證(circular reasoning): 
            陳述某命題,而其實那正是需要被證實的。(例如:神存在是因為圣經有記載,圣經存在是因為神所默示的。) 

            構成謬誤(composition fallacy): 
            當某論據的結論,是倚靠由某東西從部份至整體、或從整體至部份的錯誤特性。(例如:人類有意識,而人體和人腦都是由原子組成,所以原子都有意識。又例如:文書處 理軟件由佷多原位組(byte)組成,所以一個原位組是組成文書處理軟件的一部份。) 

            確認性偏見(confirmation bias): 
            (類似監視下的選擇)這是指一種選擇性的思想,集中於支持相信的人已相信的證據,而忽略反駁他們信念的證據。確認性偏見常見於人們以信心、傳統及成見為根據的信 念。例如,如果有些人相信祈禱的力量,相信的人只會注意到少量「有回應」的祈禱,而忽略大多數無回應的祈禱。(這表示祈禱的價值最差只是隨機,最好也只有心理上 的安慰作用。) 

            混淆相關及起因(confusion of correlation and causation): 
            (例如:玩象棋的人男性比女性多,所以男性棋藝也比女性高。又例如:兒童觀看電視的暴力場面,成長後會有暴力傾向。)但是,那是由於電視節目引致暴力,還是有暴 力傾向的兒童喜歡觀看暴力節目?真正引致暴力的原因可能是完全與電視無關。Stephen 
            Jay Gould 把相關引致的無效假設稱為「可能是人類推理上兩三種最嚴重和最普遍的錯誤」。 

            錯誤二分法/排中(excluded middle / false dichotomy): 
            只考慮極端。很多人用亞理士多德式(Aristotelian)的「非此即彼」的邏輯去解釋上下、黑白、對錯、愛惡等。(例如:你若非喜歡它,就是不喜歡它。他 如不是有罪,就是無罪。)很多時人們沒有看到在兩個極端之間出現的連續,這個宇宙也包含很多「可能」的。 

            隱藏證據(half truths / suppressed evidence): 
            故意欺騙的陳述,通常隱藏一些事實,而那是構成準確描述所必需的。 

            暗示/誘導性問題(loaded questions): 
            問題加入假設,一旦回答便顯示了一個暗示性的同意。(例如:你停止了打你的妻子嗎?) 

            無意義的問題(meaningless question): 
            (例如「上面有多高?」「一切皆可能嗎?」)「上面」描述方向,不是可衡量的單位。假如一切都證實可能,那麼「不可能」都可能出現,矛盾便出現。盡管一切不一定 證實可能,亦可以有無數的可能和無數的不可能。很多無意思的問題都包含了空廢的詞語,如 
            "is," "are," "were," "was," "am," "be," 或 "been." 

            統計性質的誤解(misunderstanding the nature of statistics): 
            (例如:大多數美國人都死在醫院內,所以應盡量遠離醫院。)「統計顯示,通常染上進食習慣的人,很少能生存?!?- Wallace Irwin 

            不當結論(non sequitur): 
            拉丁語「它沒有跟隨」的意思。推斷或結論沒有跟隨已建立的前提或證據。(例如:在月圓時出生的人較多。結論:月圓引致出生率上升。)可是,是月圓引致較多出生, 還是由於其他原因(可能是統計上的期望差異)? 

            監視下的選擇(observational selection): 
            (類似確認性偏見)指出有利的,卻忽略不利的事實。誰去過拉斯維加斯(Las 
            Vegas)賭場會見到人們在賭桌上和老虎機上贏錢,賭場經理會響鐘及鳴笛以公告勝利者,卻永不會提及失敗者。這可令人覺得勝出的機會看來頗大,但是事實卻剛剛 相反。 

            錯誤因果(post hoc, ergo propter hoc): 
            拉丁語「它發生在之後,所以它是結果?!古c不當結論類似,不過與時間有關。(例如:她去了中國之後病了,所以中國有些東西令到她病。)可能她的病是由於其他原因 ,與中國完全無關。 

            證明不存在(proving non-existence): 
            當辯者無法為他的聲稱提供證據,他可能會挑戰他的對手,叫對手證明他的聲稱不存在。(例如:證明神不存在;證明不明飛行物體未曾到過地球;等等)盡管有人可以在 特定的限制中證明不存在,如在盒中沒有某些東西,可是卻無法證明普遍性、絕對性或認知性的不存在。無人能證明一些不存在的東西。提出聲稱的人必需自己證明那聲稱 的存在。 

            扯開話題(red herring): 
            辯者改變話題,以分散注意力。 

            實體化謬誤(reification fallacy): 
            當人們把抽象的信念或假設性的構想,當作是實在的事物。如以IQ題作為真實衡量智慧的方法;由抽象的社會構想而來的種族概念(盡管基因屬性的存在),源自經揀選 的屬性組合,或者標簽某一組人;占星;耶穌;圣誕老人;等等。 

            滑坡謬誤(slippery slope): 
            一個步驟、法律、或行動的改變,可引致不良的後果。(例如:如果我們容許醫生幫助安樂死,那麼去到最後,政府會控制我們如何死。)不一定只因為我們的改變,出現 了滑坡,便會使預計的後果實現。 

            片面辯護(special pleading): 
            以新鮮或特別的聲稱,抗衡對手的陳述;展示論據時只著重主題中有利或單一的范疇。(例如:神為何在世上創造這麼多苦難?答案是:你必須明白,神自有祂神奇的安排 ,我們沒有特權去知道的。又例如:星座是準確的,但你必須先了解背後的理論。) 

            小眾統計(statistics of small numbers): 
            類似監視下的選擇。(例如:我的父母吸了一世煙,但他們從未患過癌癥。又例如:我不管其他人如何講 Toyota,我的 Toyota 
            卻從未發生過問題。)只指出少量有利數據,與整體機會并無關系?!沧g注:把 Yugo 改成 Toyota 使更易明白〕 

            稻草人謬誤(straw man): 
            創造一個虛假的情況,然後去攻擊它。(例如:進化論者認為所有事物都是隨機的。)大部份進化論者認為,在自然選擇的解釋下,可能包括偶發的成份,但并非全然依靠 隨機。抹黑你的對手只會令討論的功能偏離。 

            你我皆錯(two wrongs make a right): 
            指控其他人跟我們所做的同樣事情,為我們所作所為辯護。(例如:你有甚麼資格批評我?你也跟我做著一模一樣的事情?。┛胤降乃傅淖锱c討論本身并無關連。 

            分散注意力的謬誤(Fallacies of Distraction) 

                 * 兩難推理(False Dilemma) 
            錯謬:為多於一個答案的問題提供不足(通常兩個)的選擇,即是隱藏了一些選擇,最典型的表現是非黑即白觀點。 
                 * 例子:薩達姆是邪惡的,所以美軍是正義之師。 
                 * 解釋:除正邪之爭外,還有邪邪之爭及許多難分正邪的紛爭,所以不能單以薩達姆邪惡便認定美軍正義。 

                 * 訴諸無知(From Ignorance) 錯謬:因為不能否定,所以必然肯定,反之亦然。 
                 * 例子:沒有人能證明鬼不存在,那麼鬼肯定存在。 
                 * 解釋:總有些事是既不能否定,亦不能肯定的。除了肯定和否定,我們還可以存疑吧! 

                 * 滑坡謬誤(Slippery Slope) 錯謬:不合理使用連串因果關系。 
                 * 
            例子:遲到的學生要判死刑。因為遲到是不用功的表現;將來工作也不勤力;不勤力導致公司損失;公司損失就會倒閉;公司倒閉會使人失業;失業造成家庭問題;家庭問 題導致自殺率上升,為了防止自殺率上升,我們應判遲到的學生死刑。 
                 * 
            解釋:滑坡謬誤中假定了連串「可能性」為「必然性」。比方說,遲到是否「必然」是不用功的表現?將來工作又是否「必然」不勤力?答案可想而知。例子雖然夸張,但 其實許多時候大家亦會犯相同錯誤而不自知。 

                 * 復合問題(Complex Question) 錯謬:一條問題內包含兩個無關的重點。 
                 * 例子:你還有沒有干那非法勾當?(你有干非法勾當嗎?是否還有繼續?) 
                 * 解釋:簡單的一句提問,其實隱藏了兩個問題。你給予其中一條問題的答案,并不一定和另外一條的一樣。例如你有干非法勾當,但未必等於你還有繼續。 

            訴諸其他支持(Appeals to Motives in Place of Support) 

                 * 訴諸勢力(Appeal to Force) 錯謬:以勢力服人。 
                 * 例子:若你不想被解雇,你必須認同公司的制度。 
                 * 解釋:這是以工作機會強迫員工認同制度,員工不是依據制度好壞來決定認同與否。 

                 * 訴諸憐憫(Appeal to Pity) 錯謬:以別人的同情心服人。 
                 * 例子:希望你接受我這個多月來天天通宵撰寫的建議書。 
                 * 解釋:建議書的好壞,不在乎花了多少時間,而是取決於其內容,提出「多月來天天通宵撰寫」只為搏取同情。 

                 * 訴諸結果(Consequences) 錯謬:以討好或不討好的結果服人。 
                 * 例子:你若不聽我的話,我便打你,不準你外出,扣起你的零用。 

                 * 訴諸不中肯字詞(Prejudicial Language) 錯謬:以不中肯的字詞修飾論點。 
                 * 例子:凡是愛國的人都會認同訂立國家安全法的必要。 

                 * 訴諸大眾(Popularity) 錯謬:以被廣泛接納為理由服人。 
                 * 例子:看!人人都這樣說,還會錯嗎? 

                 * 一廂情愿(Wishful Thinking) 錯謬:以自己單方面想法作為論證根據。 
                 * 例子:因為我希望明天在戶外打球,所以明天一定天晴。 

            改變話題(Changing the Subject) 

                 * 人身攻擊(Attacking the Person) 錯謬〔一〕:以攻擊發言人代替攻擊其論點(因人廢言)。 
                 * 例子    :張廠長反對陳主任增加成本會計部的建議:「你當然說成本會計十分重要,因為你是會計主任。」 
                 * 錯謬〔二〕:由回應論點改變為攻擊論點發起人的處境。 
                 * 例子    :你竟相信那些草根階層的說話? 
                 * 錯謬〔三〕:提出「你也是!」的不恰當反問作論據。 
                 * 例子    :父:吸煙對健康不好!兒:為什麼你也吸? 

                 * 訴諸權威(Appeal to Authority) 錯謬〔一〕:訴諸討論的范疇以外的權威人士。 
                 * 例子    :經濟學家都認為愛因斯坦的相對論是不可能的。 
                 * 錯謬〔二〕:訴諸權威人士的個人意見。 
                 * 例子    :羅局長說:「學生是政府的政策下最大得益者,所以學生無權批評領導人」 
                 * 解釋    :學生是政府的政策下最大得益者只是羅局長的說話,事實上學生是否政府的政策下最大得益者,卻沒有一個客觀答案。 
                 * 錯謬〔三〕:該范疇的權威人士不是認真的回應。(例如:只是在開玩笑/喝醉。) 
                 * 例子    :「有香車自然有美人,BENZ的總公司董事長都這樣說啦!」 

                 * 匿名權威(Anonymous Authority) 錯謬:匿名的權威人士使人不能確定其權威性。 
                 * 例子:有位心理學家曾經說過,每人都有犯罪傾向。 

                 * 作風蓋過本體(Style Over Substance) 錯謬:討論者以作風蓋過事件本身使人認為其論點正確。 
                 * 例子:以他一向的對人的態度,他一定不會對你好的。 

            歸納的謬誤(Inductive Fallacies) 

                 * 輕率的歸納(Hasty Generalization) 錯謬:用作歸納總體的樣本太少。 
                 * 例子:我問了十個人,有九個說反對民主黨。結論:原來九成香港人反對民主黨。 
                 * 解釋:單憑十個人論斷香港七百萬人?未免太輕率吧。若說訪問了數萬人,得出來的結果便較有說服力。 

                 * 不具代表性的例子(Unrepresentative Sample) 錯謬:用作歸納的例子不能代表其總體。 
                 * 例子:葉繼歡持械行劫;林過云奸殺多女;歐陽炳強紙盒藏屍。香港人肯定有殺人傾向。 

                 * 不當類比(Weak Analogy) 錯謬:以兩件不相似的事件/事物作類比。 
                 * 例子:他對朋友這麼好,對女朋友一定很好呢。 

                 * 懶散的歸納(Slothful Induction) 錯謬:否定歸納得出來的恰當結論。 
                 * 例子:即使有萬多個實驗證明化學物質影響我們的感覺,我就是不相信。 

                 * 排除證據謬誤(Fallacy of Exclusion) 錯謬:故意把重要的證據隱藏,以得出不同的結論。 
                 * 例子: 

            統計三段論的謬誤(Fallacies Involving Statistical Syllogisms) 

                 * 例外(Accident) 錯謬:以概括情況加諸應有的例外情況。 
                 * 例子:政府法例規定,行走此公路的汽車最高時速為七十公里。所以即使載著快要生產的產婦,亦不可開得快過七十公里。 

                 * 相反的例外(Converse Accident) 錯謬:以例外情況加諸應有的概括情況。 
                 * 例子:我們準許瀕死的病人注射海洛英,基於人人平等,也應讓其他人注射海洛英。 

            因果的謬誤(Causal Fallacies) 

                 * 巧合謬誤(Coincidental Correlation) 錯謬:以個別情況肯定某種因果關系。 
                 * 例子:希希吃了一種藥,出現過敏反應。因此,希希認為這種藥必然導致過敏反應。 
                 * 解釋:希希遇到的只是個別例子,不能因此論斷該藥必然導致過敏反應。 

                 * 復合結果(Joint Effect) 錯謬:當兩件事都為某原因的結果時,以一事為另一事的原因。 
                 * 例子:記者報導離鄉背井的戰爭難民中的一家人:「他們因為房子被炮火所毀而逃到這里?!?#160;
                 * 解釋:炮火導致這家人的房子被毀及離鄉逃難;房子被毀并不導致這家人離開原居地。 

                 * 無足輕重(Genuine but Insignificant Cause) 錯謬:舉出無足輕重的次要原因論證,遺漏真正的主因。 
                 * 例子:吸煙使香港空氣質素每況愈下。 
                 * 解釋:導致香港空氣質素差的主因是交通公具的廢氣和天氣情況。 

                 * 倒果為因(Wrong Direction) 錯謬:顛倒事件的因果關系。 
                 * 例子:癌癥導致吸煙 
                 * 解釋:吸煙才是癌癥的原因。 

                 * 復合原因(Complex Cause) 錯謬:只指出多個原因中的其中一個為事件主因。 
                 * 例子:你一日到晚都只是玩游戲機而不溫習,難怪你考試成績那麼差。 
                 * 解釋:除了玩游戲機而不溫習外,還有其他原因,例如考試期間一時大意或者試題太難,但它們和玩游戲機一樣,不一定是主因。 

            論點缺失謬誤(Missing the Point) 

                 * 乞求/竊取論點(Begging the Question) 錯謬:以假定正確的論點得出結論。 
                 * 例子:我知道有上帝,因為《圣經》是這樣說,而《圣經》是不會錯,因為它是上帝寫的。 

                 * 不恰當結論(Irrelevant Conclusion) 錯謬:提出作支持的論據主要支持其他結論。 
                 * 例子: 

                 * 稻草人謬誤(Straw Man) 錯謬:扭曲對方論據以攻擊之。 
                 * 例子:進化論說人是由猩猩演化而來。 
                 * 解釋:進化論只是說人和猩猩有共同祖先。 

            含糊不清謬誤(Fallacies of Ambiguity) 

                 * 含糊其辭(Equivocation) 錯謬:使用有多於一個含義的字眼。 
                 * 例子:甲:喇叭中學又發生學生毆斗事件。乙:噢!是九龍那所嗎?甲:&%^%$&%$#... 
                 * 解釋:甲這里沒有表明是新界喇叭,使乙誤會成九龍的喇叭書院。 

                 * 模棱兩可(Amphiboly) 錯謬:句子結構含多種解釋方法。 
                 * 例子: 

                 * 重音謬誤(Accent) 錯謬:以重音強調某字眼或字句,達致其他意思。 
                 * 例子: 

            類目錯誤(Category Errors) 

                 * 構成謬誤(Composition) 錯謬:以總體的某部份符合某條件推斷總體均符合某條件。 
                 * 例子: 

                 * 分割謬誤(Division) 錯謬:以總體符合某條件推斷總體的所有部份均符合某條件。 
                 * 例子: 

            不根據前題的推理(Non Sequitur) 

                 * 肯定後件(Affirming the Consequent) 錯謬:所有依此結構的推論:若A則必定B;B,所以便A。 
                 * 例子:如果他在中環,他一定在港島。因此如果他現在在港島,他一定在中環。 
                 * 解釋:在港島不一定要在中環,可以在金鐘、灣仔、銅鑼灣等。因港島包含了以上各項。 

                 * 否定前件(Denying the Antecedent) 錯謬:所有依此結構的推論:若A則必定B; 非A,所以非B。 
                 * 例子:如果他在中環,他一定在港島。因此如果他現在不在中環,那麼他一定不在港島。 
                 * 解釋:不在中環,也可以在金鐘、灣仔、銅鑼灣等。因港島包含了以上各項。 

                 * 前後矛盾(Inconsistency) 錯謬:斷言兩件矛盾的事件都正確 

            posted @ 2009-04-30 13:02 OxFAN 閱讀(477) | 評論 (0)編輯 收藏

            (注:個人覺得這篇文章不錯故轉載了)

                 C++中的虛函數的作用主要是實現了多態的機制。關于多態,簡而言之就是用父類型別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數。這種技術可以讓父類的指針有“多種形態”,這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的代碼來實現可變的算法。比如:模板技術,RTTI技術,虛函數技術,要么是試圖做到在編譯時決議,要么試圖做到運行時決議。

            關于虛函數的使用方法,我在這里不做過多的闡述。大家可以看看相關的C++的書籍。在這篇文章中,我只想從虛函數的實現機制上面為大家 一個清晰的剖析。

            當然,相同的文章在網上也出現過一些了,但我總感覺這些文章不是很容易閱讀,大段大段的代碼,沒有圖片,沒有詳細的說明,沒有比較,沒有舉一反三。不利于學習和閱讀,所以這是我想寫下這篇文章的原因。也希望大家多給我提意見。

            言歸正傳,讓我們一起進入虛函數的世界。

            虛函數表

            對C++ 了解的人都應該知道虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的。簡稱為V-Table。 在這個表中,主是要一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函數。這樣,在有虛函數的類的實例中這個表被分配在了 這個實例的內存中,所以,當我們用父類的指針來操作一個子類的時候,這張虛函數表就顯得由為重要了,它就像一個地圖一樣,指明了實際所應該調用的函數。

            這里我們著重看一下這張虛函數表。在C++的標準規格說明書中說到,編譯器必需要保證虛函數表的指針存在于對象實例中最前面的位置(這是為了保證正確取到虛函數的偏移量)。 這意味著我們通過對象實例的地址得到這張虛函數表,然后就可以遍歷其中函數指針,并調用相應的函數。

            聽我扯了那么多,我可以感覺出來你現在可能比以前更加暈頭轉向了。 沒關系,下面就是實際的例子,相信聰明的你一看就明白了。

            假設我們有這樣的一個類:

            class Base {

            public:

            virtual void f() { cout << "Base::f" << endl; }

            virtual void g() { cout << "Base::g" << endl; }

            virtual void h() { cout << "Base::h" << endl; }

            };

            按照上面的說法,我們可以通過Base的實例來得到虛函數表。 下面是實際例程:

            typedef void(*Fun)(void);

            Base b;

            Fun pFun = NULL;

            cout << "虛函數表地址:" << (int*)(&b) << endl;

            cout << "虛函數表 — 第一個函數地址:" << (int*)*(int*)(&b) << endl;

            // Invoke the first virtual function

            pFun = (Fun)*((int*)*(int*)(&b));

            pFun();

            實際運行經果如下:(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)

            虛函數表地址:0012FED4

            虛函數表 — 第一個函數地址:0044F148

            Base::f

            通過這個示例,我們可以看到,我們可以通過強行把&b轉成int *,取得虛函數表的地址,然后,再次取址就可以得到第一個虛函數的地址了,也就是Base::f(),這在上面的程序中得到了驗證(把int* 強制轉成了函數指針)。通過這個示例,我們就可以知道如果要調用Base::g()和Base::h(),其代碼如下:

            (Fun)*((int*)*(int*)(&b)+0); // Base::f()

            (Fun)*((int*)*(int*)(&b)+1); // Base::g()

            (Fun)*((int*)*(int*)(&b)+2); // Base::h()

            這個時候你應該懂了吧。什么?還是有點暈。也是,這樣的代碼看著太亂了。沒問題,讓我畫個圖解釋一下。如下所示:

            注意:在上面這個圖中,我在虛函數表的最后多加了一個結點,這是虛函數表的結束結點,就像字符串的結束符“\0”一樣,其標志了虛函數表的結束。這個結束標志的值在不同的編譯器下是不同的。在WinXP+VS2003下,這個值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,這個值是如果1,表示還有下一個虛函數表,如果值是0,表示是最后一個虛函數表。

            下面,我將分別說明“無覆蓋”和“有覆蓋”時的虛函數表的樣子。沒有覆蓋父類的虛函數是毫無意義的。我之所以要講述沒有覆蓋的情況,主要目的是為了給一個對比。在比較之下,我們可以更加清楚地知道其內部的具體實現。

            一般繼承(無虛函數覆蓋)

            下面,再讓我們來看看繼承時的虛函數表是什么樣的。假設有如下所示的一個繼承關系:

            請注意,在這個繼承關系中,子類沒有重載任何父類的函數。那么,在派生類的實例中,其虛函數表如下所示:

            對于實例:Derive d; 的虛函數表如下:

            我們可以看到下面幾點:

            1)虛函數按照其聲明順序放于表中。

            2)父類的虛函數在子類的虛函數前面。

            我相信聰明的你一定可以參考前面的那個程序,來編寫一段程序來驗證。

            一般繼承(有虛函數覆蓋)

            覆蓋父類的虛函數是很顯然的事情,不然,虛函數就變得毫無意義。下面,我們來看一下,如果子類中有虛函數重載了父類的虛函數,會是一個什么樣子?假設,我們有下面這樣的一個繼承關系。

            為了讓大家看到被繼承過后的效果,在這個類的設計中,我只覆蓋了父類的一個函數:f()。那么,對于派生類的實例,其虛函數表會是下面的一個樣子:

            我們從表中可以看到下面幾點,

            1)覆蓋的f()函數被放到了虛表中原來父類虛函數的位置。

            2)沒有被覆蓋的函數依舊。

            這樣,我們就可以看到對于下面這樣的程序,

            Base *b = new Derive();

            b->f();

            由b所指的內存中的虛函數表的f()的位置已經被Derive::f()函數地址所取代,于是在實際調用發生時,是Derive::f()被調用了。這就實現了多態。

            多重繼承(無虛函數覆蓋)

            下面,再讓我們來看看多重繼承中的情況,假設有下面這樣一個類的繼承關系。注意:子類并沒有覆蓋父類的函數。

            對于子類實例中的虛函數表,是下面這個樣子:

            我們可以看到:

            1) 每個父類都有自己的虛表。

            2) 子類的成員函數被放到了第一個父類的表中。(所謂的第一個父類是按照聲明順序來判斷的)

            這樣做就是為了解決不同的父類類型的指針指向同一個子類實例,而能夠調用到實際的函數。

            多重繼承(有虛函數覆蓋)

            下面我們再來看看,如果發生虛函數覆蓋的情況。

            下圖中,我們在子類中覆蓋了父類的f()函數。

            下面是對于子類實例中的虛函數表的圖:

            我們可以看見,三個父類虛函數表中的f()的位置被替換成了子類的函數指針。這樣,我們就可以任一靜態類型的父類來指向子類,并調用子類的f()了。如:

            Derive d;

            Base1 *b1 = &d;

            Base2 *b2 = &d;

            Base3 *b3 = &d;

            b1->f(); //Derive::f()

            b2->f(); //Derive::f()

            b3->f(); //Derive::f()

            b1->g(); //Base1::g()

            b2->g(); //Base2::g()

            b3->g(); //Base3::g()

            安全性

            每次寫C++的文章,總免不了要批判一下C++。這篇文章也不例外。通過上面的講述,相信我們對虛函數表有一個比較細致的了解了。水可載舟,亦可覆舟。下面,讓我們來看看我們可以用虛函數表來干點什么壞事吧。

            一、通過父類型的指針訪問子類自己的虛函數

            我們知道,子類沒有重載父類的虛函數是一件毫無意義的事情。因為多態也是要基于函數重載的。雖然在上面的圖中我們可以看到Base1的虛表中有Derive的虛函數,但我們根本不可能使用下面的語句來調用子類的自有虛函數:

            Base1 *b1 = new Derive();

            b1->f1(); //編譯出錯

            任何妄圖使用父類指針想調用子類中的未覆蓋父類的成員函數的行為都會被編譯器視為非法,所以,這樣的程序根本無法編譯通過。但在運行時,我們可以通過指針的方式訪問虛函數表來達到違反C++語義的行為。(關于這方面的嘗試,通過閱讀后面附錄的代碼,相信你可以做到這一點)

            二、訪問non-public的虛函數

            另外,如果父類的虛函數是private或是protected的,但這些非public的虛函數同樣會存在于虛函數表中,所以,我們同樣可以使用訪問虛函數表的方式來訪問這些non-public的虛函數,這是很容易做到的。

            如:

            class Base {

            private:

            virtual void f() { cout << "Base::f" << endl; }

            };

            class Derive : public Base{

            };

            typedef void(*Fun)(void);

            void main() {

            Derive d;

            Fun pFun = (Fun)*((int*)*(int*)(&d)+0);

            pFun();

            }

            結束語

            C++這門語言是一門Magic的語言,對于程序員來說,我們似乎永遠摸不清楚這門語言背著我們在干了什么。需要熟悉這門語言,我們就必需要了解C++里面的那些東西,需要去了解C++中那些危險的東西。不然,這是一種搬起石頭砸自己腳的編程語言。

            posted @ 2009-04-30 11:02 OxFAN 閱讀(189) | 評論 (1)編輯 收藏

            2009年4月29日 #

            剛剛落戶cnblog,又來到了cppblog,這樣cnblog上的空間可能就要荒廢了,怪只能怪我沒有早發現cppblog。
            posted @ 2009-04-29 13:02 OxFAN 閱讀(151) | 評論 (0)編輯 收藏

            国产精品欧美亚洲韩国日本久久| 青青久久精品国产免费看| 久久99精品久久久久久hb无码| 久久久精品人妻一区二区三区蜜桃| 久久精品国产99国产精品亚洲| 熟妇人妻久久中文字幕| 韩国无遮挡三级久久| 久久精品国产亚洲Aⅴ香蕉| 伊人久久大香线蕉综合网站| 亚洲AV日韩精品久久久久久久| 99久久99这里只有免费费精品| 国产综合久久久久| 内射无码专区久久亚洲| 欧美熟妇另类久久久久久不卡| 国产成人久久精品麻豆一区| 一本大道久久香蕉成人网 | 久久久久夜夜夜精品国产| 久久九九久精品国产| 久久婷婷成人综合色综合| 亚洲国产成人久久笫一页| 久久国产精品99久久久久久老狼| 国产精品美女久久福利网站| 亚洲天堂久久精品| 国产高潮国产高潮久久久| 色综合久久夜色精品国产| 大香网伊人久久综合网2020| 国产毛片欧美毛片久久久 | 中文国产成人精品久久不卡| 久久国产一片免费观看| WWW婷婷AV久久久影片| 久久AV高清无码| 久久无码人妻一区二区三区午夜| 亚洲午夜精品久久久久久浪潮 | 久久无码一区二区三区少妇| 国产成人精品久久| 国产真实乱对白精彩久久| 亚洲国产精品人久久| 久久国产成人精品麻豆| 亚洲国产成人久久精品影视| 国产精品久久久久久福利漫画| 久久久久久久99精品免费观看|