C++語言常見問題解答(1) (轉)

worldblog發表於2007-12-10
C++語言常見問題解答(1) (轉)[@more@]C++語言常見問題解答(1) 中譯者:葉秉哲 (2001-04-27 13:05:08)

 
======================================= 
                                               (US comp.lang.c++ 的 FAQ 中譯) 
 
 
 
      原作者:Marshall Cline (cline@cheetah.ece.clarkson.edu) 
                             (cline@parashift.com) 
      中譯者:葉秉哲 (william@tiger.cis.nctu.edu.tw) 
 
      原檔案:USENET comp.lang.c++ FAQ, Jan 31, 1996. 
 
    版權宣告:完全依照原作者 Marshall Cline 於此檔案中所示之版權事項 
              (請見下文之 "COPYRIGHT" 部份)。 
              如欲對本中譯檔案作授權事項之外的處理,請先洽本譯者。 
 
    責任事項:完全比照原作者 Marshall Cline 於此檔案中所示之宣告事項 
              (請見下文之 "NO WARRANTY" 部份)。 
 
    中譯事項:筆者雖盡力使此中譯檔案合乎信、達的要求,但仍恐有未逮之處, 
              故有任何出入之處,請以原文為準。 
              任何筆者為中譯、詮釋所需而加註的地方,都以 【譯註】 符號 
              標示出來。 
 
    本譯文位置:以 URL (Uniform Re Locator) 格式說明。 
       : 
         ftp://ftp.cis.nctu.edu.tw/Documents/News/C-faq/c-cppfaq.zip 
      WWW 使用者: 
         ftp://ftp.cis.nctu.edu.tw/Documents/News/C-faq/Index.html 
      各大 BBS 的 programming 精華區也可能收錄,但以前述地點最新。 
      爾後,隨原檔案之新版而異動時,會在 news:tw.bbs.comp.language 釋出。 
 
     本檔案中譯的授權: 
 
    --- --- --- --- ---  Quote Begin  --- --- --- --- --- 
    From cline@cheetah.ece.clarkson.edu Mon Oct 10 11:56:59 1994 
    Return-Path:  
    Received: from cheetah.ece.clarkson.edu by cis.nctu.edu.tw (4.1/SMI-4.1) 
            id AA18895; Mon, 10 Oct 94 11:56:46 CST 
    Received: by cheetah.ece.clarkson.edu (4.1/SMI-4.1) 
            id AA06374; Sun, 9 Oct 94 23:59:49 EDT 
    Date: Sun, 9 Oct 94 23:59:49 EDT 
    From: cline@cheetah.ece.clarkson.edu (Marshall Cline) 
    Message-Id: <9410100359.AA06374@cheetah.ece.clarkson.edu> 
    To: is80001@cis.nctu.edu.tw 
    In-Reply-To: William Yeh's message of Sat, 24 Sep 94 10:31:48 CST 
            <9409240231.AA20537@cissun51.cis.nctu.edu.tw> 
    Subject: "C++ FAQ" book from Addison-Wesley 
    Reply-To: cline@sun.soe.clarkson.edu (Marshall Cline) 
    Status: OR 
 
    >Date: Sat, 24 Sep 94 10:31:48 CST 
    >From: is80001@cis.nctu.edu.tw (William Yeh) 
    >Newsgroups: comp.lang.c++ 
    >X-Newsreader: TIN [version 1.2 PL2] 
    > 
    >Hi, 
    > 
    >  We, students at Department of Computer & Information Science, enjoy 
    >your electronic-formed C++ FAQ very much.  We'd like to translate it 
    >into our native Chinese for those having difficulty to read English 
    >articles. 
    > 
    >  The translated article is meant to be used as an electronic document 
    >on Internet, and not for commercial use.  We, therefore, ask for your 
    >grants for this translation. 
    > 
    >  Regards. 
    > 
    >student at cis.nctu.edu.tw 
    >-- 
    >-- -- -- -- -- -- -- -- -- -- -- --  -- -- -- -- -- -- -- -- -- -- -- -- 
    > William Yeh                        | E- address: 
    >                                    |   is80001@cis.nctu.edu.tw 
    > Dept. of Computer & Info. Science  |   u8023001@cc.nctu.edu.tw 
    > National Chiao-Tung University,    |   william.bbs@bbs.cis.nctu.edu.tw 
    > Hsinchu, Taiwan, R.O.C.            | 
    >-- -- -- -- -- -- -- -- -- -- -- --  -- -- -- -- -- -- -- -- -- -- -- -- 
 
    That sounds like a wonderful a. 
    Pession granted. 
    M. 
    --- --- --- --- ---  Quote End  --- --- --- --- --- 
 
 
 
    【中譯對照表】 
 
      底下列出本文出現的專有名詞、其他重要的詞兒,與譯者採用的中譯,視上下 
      文情況,它們也可能會有兩種以上的譯名。可能的話,括號中也會附上一些其 
      他書籍文章中常見的譯法。 
 
        abstraction             抽象化. 
        access                  存取. 
        access function         存取. 
        alias                   別名. 
        argument                引數. 
        arity                   元數. 
        assignment              設定. 
        associativity           結合律. 
        base class              基底類別. 
        binding                 繫結. 
        call                    呼叫. 
        class                   類別、物件類別. 
        composition             成份、零件. 
        constructor             建構子(建構元). 
        container               容器. 
        container class         容器類別. 
        data member             資料成員. 
        declaration             宣告                            . 
        declare                 宣告                            . 
        default                 預設、內定. 
        define                  定義                            . 
        definition              定義                            . 
        dereference             解參用、解參考. 
        derive                  衍生. 
        destructor              解構子(解構元). 
        dispatch                分派、函式分派. 
        dynamic                 動態. 
        encapsulation           封裝、封裝性. 
        exception               例外、例外狀況(異常). 
        exception handling      例外處理. 
        explicit                明顯的、外顯的                  . 
        expression              運算式. 
        friend                  夥伴. 
        function                函式. 
        genericity              泛型. 
        header file             標頭檔(引入檔、含括檔). 
        hide                    遮蔽. 
        hierarchy               階層. 
        identity                個體識別. 
        implement               實作                            . 
        implementation          實作                            . 
        inherit                 繼承                            . 
        inheritance             繼承                            . 
        inline                  行內(列內、內嵌). 
        inspector               查詢子. 
        instance                案例、實體(個體). 
        instantiate             案例化、實體化                  . 
        instantiation           案例                            . 
        key                 關鍵字、保留字. 
        mangle                  簽名編碼                        . 
        mangling                簽名編碼                        . 
        member                  成員. 
        member function         成員函式. 
        member            成員物件. 
        method                  運作方法、運算方法. 
        module                  模組. 
        multiple inheritance    多重繼承. 
        mutator                 更動子. 
        object                  物件(個體). 
        OO                      物件導向(個體導向). 
                             物件導向程式設計. 
        operator                運運算元. 
        overload                多載(過荷、負載)              . 
        overloading             多載(過荷、負載)              . 
        override                覆蓋、改寫. 
        parameter               引數. 
        persistence             持續性(永續性、持固性)        . 
        persistent object       持續性物件. 
        pointer                 指標. 
        polymorphism            多型(同名異式). 
        precedence              優先序. 
        pretty printer          美編工具. 
        private                 私有. 
        protected               保護. 
                       原型、函式原型(雛型). 
        public                  公共、公有. 
        pure virtual function   純虛擬函式. 
        reference               參考、參考值. 
        relation                關係. 
        return value            傳回值. 
        semantics               語意. 
        signature               簽名、型態簽名. 
        smart pointer           聰明的指標. 
        specialization          特異化、特殊化. 
        statement               陳述、指令(指述). 
        static                  靜態. 
        structure               結構、記錄. 
        subclass                子類別、子代類別. 
        subtype                 子型別、子型態. 
        superclass              父類別、親代類別. 
        syntax                  語法、文法. 
        template                樣版(模版). 
        throw                   丟出. 
        type                    型態、型別. 
        virtual                 虛擬. 
        virtual function        虛擬函式. 
 
 
    【中譯版本異動紀錄】 
 
    85.02. 對整篇譯文做比較多一點的修飾。 
 
    84.05. 修飾些 method 相關的譯名。 
 
    84.03. 修飾些 persistence、instance 相關的譯名。 
 
    84.01. 一些譯文修飾、增加此中譯檔案的 ftp 棲身處說明。 
           將覆蓋 (override) 與遮蔽 (hide) 二詞更明顯地區分開來。 
           對「聰明的指標」(smart pointer) 加一點詮釋。 
 
    83.12. 一些譯文修飾、將 "method" 統一譯為「運算方法」。 
 
    83.11. 第一次釋出,原載於交大資科系刊「資訊人園地」。 
 
 
    底下就是此 USENET comp.lang.C++ FAQ 檔案的正文。 
 
 
 
== Part 1/4  ============================ 
 
【譯註】原檔案因篇幅過長,在釋出時就已分成四份。 
 
comp.lang.c++ Frequently Asked Questions list (with answers, fortunately). 
Copyright (C) 1991-96 Marshall P. Cline, Ph.D. 
Posting 1 of 4. 
 
 
1/96 : 
 * 關於恢復 fron.soe.clarkson.edu 的 anonymous ftp 方式仍無下文。 
 * 本月份沒什麼變動。 
 
9/95 更新: 
 * 加入 FAQ 41:以變數做為多維陣列的第一維度。 
 * 加入 FAQ 123:關於 "Numerical Recipes" 的程式。 
 * 加入第 20 節 ("程式庫")。內容還很少,但總是個開端。 
 * 修正 FAQ 30 的錯誤(少了 "i" 變數)。 
 * 加入 FAQ 124:使用動態連結以避免過於龐大的執行檔。 
 * 加入 FAQ 32:想在 binary 下 "reopen" cin 及 cout 的問題。 
 * 加入 ftp ANSI/ISO Committee Draft 的資訊 (FAQ 7)。 
 
7/95 更新: 
 * 小地方(除了下面會提到的 FTP 地點的變動之外)。 
 
6/95 更新: 
 * 更正訂閱 ANSI-C++ Draft 的電子郵遞信箱。 
 * 新增關於浮點運算的 FAQ [Phil Staite 所提的]。 
 * 新增關於多維陣列的 FAQ [Doug Shapter 所提的]。 
 * 新增關於中斷服務常式 (ISR),以及指向成員函式的指標之 FAQ。 
 * 重排關於「用 'new' 來某些類別的物件」FAQ 的位置。 
 
5/95 更新: 
 * 一些語句修飾。 
 
4/95 更新: 
 * 新增 BC++  方面常見的問題。 
 * 更改 NIHCL 的 ftp 位址。 
 * 新增解釋:"ARM" 代表 "Annotated Reference Manual"。 
 
3/95 更新: 
 * 新增關於 "delete this" 的問題。 
 * 新增兩則關於 iostreams 與 eof 的問題。 
 * 更正些  emacs 的 "c-mode" 和 "cc-mode" 的專案。 
 
1/95 更新: 
 * 此檔案的中譯版出來了;底下再詳述之。 
 
12/94 更新: 
 * 新增關於 STL 的 FAQ(放在 #115)。 
 * 新增關於簽名編碼的 FAQ(放在 #119)。 
 * 更正「『成份』與『私有繼承』之比較」這項 FAQ 裡面的一些打字錯誤。 
 * 更正一些拼字錯誤。 
 
11/94 更新: 
 * 加入「FAQ 書」和「FAQ 檔案」的區別資訊。 
 * 其他字面上的修飾。 
 
10/94 更新: 
 * 修正一些打字錯誤。 
 
9/94 更新: 
 * 一點文字上的修飾。 
 
8/94 更新: 
 * 加入 "typeid" 和 "dynamic_cast" 的新規定。 
 * 加入 "mutable" 和 "const_cast" 的新規定。 
 * 重寫大部份的回答部份,使其更一致些。 
 * 原文的引號改為 "..." 而不是 `...' 或 ``...'' 。 
 * 有程式碼例子的那一行以 TAB 起頭;其他行則否。 
   【譯註】本中譯版以 8 個英文空白字元代替 TAB。 
 * 所有東西都編輯過了;到處都有小更動。 
 
 
======================= 
■□ 第1節:內容介紹 
======================= 
 
        DOCUMENT:    Frequently-Asked-Questions for comp.lang.c++ 
        REVISION:    Jan 31, 1996 
 
        檔案不等於書本:這份 C++ FAQ 檔案和「FAQ 書」是不一樣的。“FAQ 書” 
                  ("C++ FAQs", Addison-Wesley, 1995) 是這篇檔案的五倍大。 
                  底下有更詳細的介紹。 
 
        AUTHOR:      Marshall P. Cline, Ph.D. 
                     Paradigm Shift, Inc. 
                     One Park St. / Norwood, NY  13668 
                     voice: 315-353-6100 
                     fax:   315-353-6110 
                     : cline@parashift.com 
 
        COPYRIGHT:   Copyright (C), 1991-96 Marshall P. Cline, Ph.D. 
                     Permission to copy all or part of this work is granted, 
                     provided that the copies are not made or distributed 
                     for resale (except a nominal copy fee may be charged), 
                     and provided that the AUTHOR, COPYRIGHT, & NO WARRANTY 
                     sections are retained verbatim and are displayed 
                     conspicuously.  If anyone needs other permissions that 
                     aren't covered by the above, please contact the author. 
 
        NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS.  THE AUTHOR 
                     PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR 
                     IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH 
                     RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY 
                     PARTICULAR PURPOSE. 
 
        版權宣告:Copyright (C), 1991-96 Marshall P. Cline, Ph.D. 
                  複製本檔案全部或部份的內容,若合乎下述諸項要求,則允許之 
                  :不得為轉售之目的而製作或傳播任何複製品(但可索取名義上 
                  的傳播手續費),並且作者欄、版權宣告及責任事項的部份,要 
                  一字不漏地、醒目地顯示出來。若您需要此處未提及的授權事項 
                  ,請洽本作者。 
 
        責任事項:這份檔案是供您參考用的。對於本作品可能造成的營利性、或任 
                  何特殊場合適用性之保障,作者概不負責,不論是否曾明白地指 
                  出或暗示。 
 
          【譯註】上述的「版權宣告」與「責任事項」譯文,僅供參考,一切請以 
                  原文為準。譯者對它們亦概不負責…… ;-> 
 
        檔案取得方法:  舊的 FTP 地點不能用了。我正在尋找新的地點, 
                        請密切注意下個月的這個地方。 
                        請不要寄信來推薦新的地點(我的信箱會爆滿的 :) 
 
          【譯註】臺灣使用者,請到以下地點,或其 AFS client 取得: 
                  ftp://NCTUCCCA.edu.tw/USENET/FAQ/comp/lang/c++/FAQ* 
 
        其他資訊:comp.lang.c FAQ 每個月都會出現在該討論區中, 
                  該檔案的維護者是 Steve Summit (scs@eskimo.com) 。 
 
        中文翻譯:用 "Big5" 內碼(在臺灣最廣為使用的 16 位元中文內碼)儲存 
                  的中文譯文,可用 anonymous ftp 到以下地點取得: 
             ftp://ftp.cis.nctu.edu.tw/Documents/News/C-faq/c-cppfaq.zip 
 
================================= 
● 1A:「FAQ 書」與「FAQ 檔案」 
================================= 
 
Addison-Wesley 已出版了由 Cline 與 Lomow 合著的 "C++ FAQs" (1995, ISBN 
0-201-58958-3) 一書,許多人對該書和這篇檔案的關係感到好奇,一些沒看過該書 
的人,也擔心本文是否會和它相同。此處將回答這些問題。 
 
「FAQ 書」(於 Oct. 94 上市)大體上和本文的觀念一致,但該書約為本文的5倍 
大,還包括了數千則互動參考資訊、參考資料、專案,及許多的程式例子。 
 
============= 
● 1B:目錄 
============= 
 
========== POSTING #1 ========== 
 
第1節:內容介紹 
---------------- 
⊙1A:「FAQ 書」與「FAQ 檔案」 
⊙1B:目錄 
⊙1C:術語及常用的縮寫 
 
第2節:我該如何參與討論?(發信之前請務必一讀) 
------------------------------------------------ 
Q1:我該在哪個討論區中發問? 
Q2:我該怎麼提出「我的程式有毛病」的問題呢? 
 
第3節:周遭的、管理上的事項 
---------------------------- 
Q3:什麼是 OOP?什麼是 C++? 
Q4:C++ 的優點是什麼? 
Q5:誰在用 C++? 
Q6:有任何 C++ 標準化方案在進行嗎? 
Q7:該到哪裡索取最新的 ANSI-C++ 標準草案? 
Q8:C++ 對 ANSI-C 回溯相容嗎? 
Q9:多久才能學會 C++? 
 
第4節:C++ 的基礎 
------------------ 
Q10:什麼是類別(class)? 
Q11:什麼是物件(object)? 
Q12:什麼是參考(reference)? 
Q13:如果設定某值給參考會怎麼樣? 
Q14:怎樣才能將參考改設成別的物件? 
Q15:何時該用參考,何時又該用指標? 
Q16:行內函式是做什麼的? 
 
第5節:建構子和解構子 
---------------------- 
Q17:建構子(constructor)是做什麼的? 
Q18:怎樣才能讓建構子呼叫另一個同處一室的建構子? 
Q19:解構子(destructor)是做什麼的? 
 
第6節:運運算元多載 
------------------ 
Q20:運運算元多載(operator overloading)是做什麼的? 
Q21:哪些運運算元可以/不能被多載? 
Q22:怎樣做一個 "**"「次方」運運算元? 
 
第7節:夥伴 
------------ 
Q23:夥伴(friend)是什麼? 
Q24:「夥伴」違反了封裝性嗎? 
Q25:夥伴函式的優缺點? 
Q26:「夥伴關係無繼承及遞移性」是什麼意思? 
Q27:應該替類別宣告個成員函式,還是夥伴函式? 
 
第8節:輸入/輸出: 和  
--------------------------------------------- 
Q28:該怎樣替 "class Fred" 提供輸出功能? 
Q29:為什麼我該用  而不是以前的 ? 
Q30:為什麼我處理輸入時,會超過檔案的結尾? 
Q31:為什麼我的程式執行完第一次迴圈後,會對輸入的要求不加理睬? 
Q32:在 DOS 及 OS/2 的 binary 模式下,要怎樣來 "reopen" cin 及 cout? 
 
========== POSTING #2 ========== 
 
第9節:自由記憶體管理 
---------------------- 
Q33:"delete p" 會刪去 "p" 指標,還是它指到的資料,"*p" ? 
Q34:我能 "free()" 掉由 "new" 配置到的、"delete" 掉由 "malloc()" 配置到的 
     記憶體嗎? 
Q35:為什麼該用 "new" 而不是老字號的 malloc() ? 
Q36:為什麼 C++ 不替 "new" 及 "delete" 搭配個 "realloc()" ? 
Q37:我該怎樣配置/釋放陣列? 
Q38:萬一我忘了將 "[]" 用在 "delete" 由 "new Fred[n]" 配置到的陣列,會發生 
     什麼事? 
Q39:成員函式做 "delete this" 的動作是合法的(並且是好的)嗎? 
Q40:我該怎麼用 new 來配置多維陣列? 
Q41:C++ 能不能做到在執行時期才指定陣列的長度? 
Q42:怎樣確保某類別的物件都是用 "new" 建立的,而非區域或整體/靜態變數? 
 
第10節:除錯與錯誤處理 
------------------------ 
Q43:怎樣處理建構子的錯誤? 
Q44:如果建構子會丟出例外的話,該怎麼處理它的資源? 
 
第11節:Const 正確性 
---------------------- 
Q45:什麼是 "const correctness"? 
Q46:我該早一點還是晚一點讓東西有常數正確性? 
Q47:什麼是「const 成員函式」? 
Q48:若我想在 "const" 成員函式內更新一個「看不見的」資料成員,該怎麼做? 
Q49:"const_cast" 會不會喪失最佳化的可能? 
 
第12節:繼承 
-------------- 
Q50:「繼承」對 C++ 來說很重要嗎? 
Q51:何時該用繼承? 
Q52:怎樣在 C++ 中表現出繼承? 
Q53:把衍生類別的指標轉型成指向它的基底,可以嗎? 
Q54:Derived* --&gt Base* 是正常的;那為什麼 Derived** --&gt Base** 則否? 
Q55:衍生類別的陣列「不是」基底的陣列,是否表示陣列不好? 
 
⊙12A:繼承--虛擬函式 
Q56:什麼是「虛擬成員函式」? 
Q57:C++ 怎樣同時做到動態繫結和靜態型別? 
Q58:衍生類別能否將基底類別的非虛擬函式覆蓋(override)過去? 
Q59:"Warning: Derived::f(int) hides Base::f(float)" 是什麼意思? 
 
⊙12B:繼承--一致性 
Q60:我該遮蔽住由基底類別繼承來的公共成員函式嗎? 
Q61:圓形 "Circle" 是一種橢圓 "Ellipse" 嗎? 
Q62:對「圓形是/不是一種橢圓」這兩難問題,有沒有其他說法? 
 
⊙12C:繼承--存取規則 
Q63:為什麼衍生的類別無法存取基底的 "private" 東西? 
Q64:"public:"、"private:"、"protected:" 的差別是? 
Q65:當我改變了內部的東西,怎樣避免子類別被破壞? 
 
⊙12D:繼承--建構子與解構子 
Q66:若基底類別的建構子呼叫一個虛擬函式,為什麼衍生類別覆蓋掉的那個虛擬函 
     數卻不會被呼叫到? 
Q67:衍生類別的解構子應該外顯地呼叫基底的解構子嗎? 
 
⊙12E:繼承--Private 與 protected 繼承 
Q68:該怎麼表達出「私有繼承」(private inheritance)? 
Q69:「私有繼承」和「成份」(composition) 有多類似? 
Q70:我比較該用哪一種:成份還是私有繼承? 
Q71:我應該用指標轉型方法,把「私有」衍生類別轉成它的基底嗎? 
Q72:保護繼承 (protected inheritance) 和私有繼承有何關連? 
Q73:"private" 和 "protected" 的存取規則是什麼? 
 
第13節:抽象化(abstraction) 
------------------------------- 
Q74:分離介面與實作是做什麼用的? 
Q75:在 C++ 裡,我該怎樣分離介面與實作(像 Modula-2 那樣)? 
Q76:ABC ("abstract base class") 是什麼? 
Q77:「純虛擬」(pure virtual) 成員函式是什麼? 
Q78:怎樣替整個類別階層提供列印的功能? 
Q79:何時該把解構子弄成 virtual? 
Q80:虛擬建構子 (virtual constructor) 是什麼? 
 
========== POSTING #3 ========== 
 
第14節:程式風格指導 
---------------------- 
Q81:有任何好的 C++ 程式寫作的標準嗎? 
Q82:程式撰寫標準是必要的嗎?有它就夠了嗎? 
Q83:我們的組織該以以往 C 的來決定程式撰寫標準嗎? 
Q84:我該在函式中間或是開頭來宣告區域變數? 
Q85:哪一種原始檔命名慣例最好? "foo.C"? "foo.cc"? "foo.cpp"? 
Q86:哪一種標頭檔命名慣例最好? "foo.H"? "foo.hh"? "foo.hpp"? 
Q87:C++ 有沒有像 lint 那樣的指導原則? 
 
第15節:Smalltalk 程式者學習 C++ 之鑰 
--------------------------------------- 
Q88:為什麼 C++ 的 FAQ 有一節討論 Smalltalk?這是用來 Smalltalk 的嗎? 
Q89:C++ 和 Smalltalk 的差別在哪? 
Q90:什麼是「靜態型別」?它和 Smalltalk 有多相似/不像? 
Q91:「靜態型別」與「動態型別」哪一種比較適合 C++? 
Q92:怎樣分辨某個 C++ 物件程式庫是否屬於動態型別的? 
Q93:在 C++ 裡怎樣用繼承?它和 Smalltalk 有何不同? 
Q94:Smalltalk/C++ 不同的繼承,在現實裡導致的結果是什麼? 
Q95:學過「純種」的 OOPL 之後才能學 C++ 嗎? 
Q96:什麼是 NIHCL?到哪裡拿到它? 
 
第16節:參考與數值語意 
------------------------ 
Q97:什麼是數值以及參考語意?哪一種在 C++ 裡最好? 
Q98:「虛擬資料」是什麼?怎麼樣/為什麼該在 C++ 裡使用它? 
Q99:虛擬資料和動態資料有何差別? 
Q100:我該正常地用指標來配置資料成員,還是該用「成份」(composition)? 
Q101:動態配置成員物件有三個因素,它們的相對代價是多少? 
Q102:"inline virtual" 的成員函式真的會被 "inline" 嗎? 
Q103:看起來我不應該用參考語意了,是嗎? 
Q104:參考語意效率不高,那麼我是否應該用傳值呼叫? 
 
========== POSTING #4 ========== 
 
第17節:和 C 連結/和 C 的關係 
-------------------------------- 
Q105:怎樣從 C++ 中呼叫 C 的函式 "f(int,char,float)"? 
Q106:怎樣才能建一個 C++ 函式 "f(int,char,float)",又能被 C 呼叫? 
Q107:為什麼 linker 有這種錯誤訊息:C/C++ 函式被 C/C++ 函式呼叫到? 
Q108:該怎麼把 C++ 類別的物件傳給/傳自 C 的函式? 
Q109:C 的函式能不能存取 C++ 類別的物件資料? 
Q110:為什麼我總覺得 C++ 讓我「離機器更遠了」,不像 C 那樣? 
 
第18節:指向成員函式的指標 
---------------------------- 
Q111:「指向成員函式的指標」和「指到函式的指標」的型態有差別嗎? 
Q112:怎樣把指向成員函式的指標傳給 signal handler、X event callback 等等? 
Q113:當我想以成員函式做為中斷服務常式 (ISR) 時,為什麼產生(型態不 
      符)的錯誤? 
Q114:為什麼我取不出 C++ 函式的位址? 
Q115:怎樣宣告指向成員函式的指標陣列? 
 
第19節:容器類別與 template 
----------------------------- 
Q116:怎樣自一個連結串列/雜湊表等等裡面,插入/存取/改變元素? 
Q117:「樣版」(template)的用意是什麼? 
Q118:"function template" 的語法/語意是什麼? 
Q119:"class template" 的語法/語意是什麼? 
Q120:什麼是「引數化型別」(parameterized type)? 
Q121:「泛型」(genericity)是什麼? 
 
第20節:程式庫 
---------------- 
Q122:怎樣拿到 "STL"? 
Q123:怎樣 ftp 到 "Numerical Recipes" 附的程式? 
Q124:為什麼我的執行檔會這麼大? 
 
第21節:特定的細節 
------------------------ 
Q125:GNU C++ (g++) 把小程式造出大大的執行檔,為什麼? 
Q126:有 YACC 的 C++ 文法嗎? 
Q127:什麼是 C++ 1.2?  2.0?  2.1?  3.0? 
Q128:如果簽名編碼標準化了,我能否將不同廠商編譯器產生的程式碼連結起來? 
 
第22節:其他的技術和環境的事項 
-------------------------------- 
⊙22A:其他的技術事項 
Q129:為什麼有 static 資料成員的物件類別產生了 linker 錯誤? 
Q130:"struct" 和 "class" 關鍵字差別在哪? 
Q131:為什麼不能以函式的傳回值來多載(overload)它? 
Q132:什麼是「持續性」?什麼是「持續性物件」? 
Q133:為什麼浮點數 (floating point) 這麼不精確?為什麼這段程式不會印出 0.43? 
 
⊙22B:其他環境下的瑣事 
Q134:有任何 TeX 或 LaTeX 的巨集,能處理 "C++" 的留白效果(spacing)嗎? 
Q135:在哪兒可拿到 C++2LaTeX 這個 C++原始碼的 LaTeX 美編工具(pretty 
      printer)? 
Q136:該到哪裡取得 "tgrind" 這個 C++/C/etc 的原始碼美編工具? 
Q137:有給 GNU emacs 編輯器用的 C++-mode 嗎?有的話,該怎麼拿? 
Q138:我要到哪兒得到和作業系統相關的 FAQs( 譬如:BC++、DOS、Windows 等等)? 
Q139:為什麼我的 DOS C++ 程式說 "Sorry: floating point code not linked" 
      “抱歉,浮點運算程式碼未連結進來”? 
Q140:為什麼當我沒執行 BC45 IDE 的話,BC++ 做出來的 Windows 應用程式就不能用? 
 
========================= 
● 1C:術語及常用的縮寫 
========================= 
 
這兒是一些此檔案所採用的縮寫: 
 
    字彙        意義 
    ====        =========== 
    fn          function ,函式(單數型) 
    fns         functions,函式(複數型) 
    param       parameter,引數 
    ptr         pointer,指標,C/C++ 的語法元素,宣告法:  int * p; 
    ref         reference,參考,C++ 的語法元素,宣告法:  int & r; 
    OO          object-oriented,物件導向 
    OOP         object-oriented programming,物件導向程式設計 
    OOPL        object-oriented programming language,物件導向語言 
    method      運作行為,"member function 成員函式" 的另一種說法 
                【譯註】"method" 是源自 Smalltalk 的術語,很常用於 OO 界。 
 
 
======================================================= 
■□ 第2節:我該如何參與討論?(發信之前請務必一讀) 
======================================================= 
 
Q1:我該在哪個討論區中發問? 
 
Comp.lang.c++ 是討論 C++語言本身最好的地方(譬如:C++ 程式設計、語法、風格 
)。其他討論區是用來討論特定的系統(譬如:MS Windows 或是 ),或是其他 
和 C++語言不直接相關的主題(譬如:怎樣使用你的編譯器)。底下列出一些非常熱 
門的討論區,並從它們的 FAQs 中摘錄些片斷,應該能讓您明瞭它們最常討論哪些課 
題。 
 
  comp.os.ms-windows.programmer.tools 
     此區是用來討論有關 Windows 軟體發展系統工具的選擇及使用。 
  comp.os.ms-windows.programmer.misc 
     此乃論及其餘 Windows 軟體發展之事項。 
  [有個 FAQ 列表,列出所有 comp.os.ms-windows.programmer.* 討論區] 
     FAQ 5.7.1.  在 DLL 中存取 C++ 的物件類別 
     FAQ 6.1.1.  以 MDI 子視窗做出對話方塊 [用 OWL] 
     FAQ 6.2.1.  把禁能的選項致能起來 [用 MFC] 
     FAQ 8.1.5.  使用 windows.h 的 STRICT 符號定義 
     FAQ 10.  程式設計參考資料 
 
  comp.os.msdos.programmer 
     許多信件都是關於程式語言產品的(主要是 Borland 和 )。 
     FAQ 301. 怎樣才能讀取字元而不 [等待] Enter 鍵? 
     FAQ 412. 怎樣讀取、建立、更改及刪除磁片標名? 
     FAQ 504. 怎樣設定 COM 埠,以用它來傳輸資料? 
     FAQ 602. C 程式怎樣才能送控制碼給印表機? 
     FAQ 606. 怎樣才能得知 Microsoft 滑鼠的位置及按鈕狀態? 
     FAQ 707. 怎樣寫常駐程式(TSR)工具? 
     FAQ B0.  怎樣連繫 [Borland, Microsoft] 等公司? 
     [注意:這份 FAQ 不在 rtfm.mit.edu 裡;而在 Simtel 
            (譬如 oak.oakland.edu) in /pub/msdos/info/faqp*.zip 以及 Garbo 
            (garbo.uwasa.fi) in /pc/doc-net/faqp*.zip] 
  comp.os.msdos.programmer.turbovision [Borland 的文字模式應用程式骨架] 
 
  comp.unix.programmer 
     FAQ 4.5)  怎樣使用 popen() 開啟行程以讀寫之? 
     FAQ 4.6)  怎樣在 C 程式裡 sleep() 一秒以內? 
 
  comp.unix. (包含 SunOS 4.x 和 Solaris) 
     FAQ 4)  Signal  
     FAQ 5)  等待子行程 Exit 
 
  gnu.g++.help 
     FAQ: 到哪裡找 C++ 的 demangler(反簽名編碼器)? 
     FAQ: 哪裡有 Solaris 2.x 版的 gcc/g++ 位元檔? 
     FAQ: 有 g++ 2.x 的檔案嗎? 
  gnu.g++. [g++ 的臭□列表 -- 請見 g++ 的檔案] 
 
  comp.lang.c 
     FAQ 1.10: 我搞糊塗了。NULL 保證一定是 0,但是 null 指標卻不是? 
     FAQ 2.3:  那麼,在 C 裡頭「指標和陣列等價」是什麼意思? 
     FAQ 4.2:  [為什麼 "printf("%dn," i++ * i++);" 有問題?] 
     FAQ 7.1:  怎樣寫一個接收不定數目引數的函式? [stdarg.h 或是 varargs.h] 
     FAQ 10.4: 怎麼宣告一個指向某種函式的指標陣列,而該函式的傳回值為: 
               指向另一個傳回字元指標的函式? 
 
並請參考看看 comp.graphics、comp.sources.wanted、comp.programming,以及 
comp.object(它的 FAQ 是個很棒的 OOP 入門、術語觀念概論檔案)。請記住: 
comp.std.c++ 是專門討論和研議中的 ANSI/ISO C++ 標準方案(下文會提)“直接 
”相關的事項。 
 
同時到上述信區和 comp.lang.c++ 去問同一個問題,幾乎是沒必要的(你是知道的 
,特定系統信區的讀者不用機器語言寫程式)。只因你的問題「真的很要緊」,就到 
處發問,是個很壞的習慣。如果你在「正確的」信區沒得到迴音,且認為你非得在這 
兒發信不可,請至少考慮一下,將這兒的回信重導回原來那個適當的信區。 
 
在任何信區發問之前,你應當先讀讀它的 FAQ。你想問的可能就在上面,這樣就可省 
下你發信的時間,以及全世界數以千計的人類讀你的信的時間。回答已經是 FAQ問題 
的人,可能會因為白白浪費時間而煩擾不已;他們也可能會給你錯誤或不完整的解答 
,因為他們也沒看過 FAQ。 
 
「常見問題解答」檔案每天 24 小時都可由 anonymous ftp (rtfm.mit.edu 的 
/pub/usenet/comp.what.ever) 或是  server (寄一則內容為 "help" 的信到 
mail-server@rtfm.mit.edu) 來取得。欲知詳情,請見 "Introduction to the 
*.answers newsgroups" 這份檔案,它在 news.answers 或 news.announce.newusers 
(這兒還有許多必須一讀的檔案)中找到。 
 
======================================== 
 
Q2:我該怎麼提出「我的程式有毛病」的問題呢? 
 
底下是一些建議,讓 comp.lang.c++ 的讀者能幫你解決程式設計的問題。 
 
1. 請讀讀上一個問題,以確定你的問題是針對 C++語言本身,而和你的程式設計系 
   統(譬如:繪圖、印表機、裝置……)或是編譯環境(譬如:「整合環境掛了」 
   、「怎樣消除xxxx警告訊息」、「怎樣連結程式庫」)完全無關。如果你想知道 
   為什麼你 OWL程式中的虛擬函式 CmOk() 沒被呼叫到,你的問題可能比較適合放 
   在 Windows程式設計的信區。如果你能寫個獨立的小程式,而它會讓編譯器產生 
   和你那個 OWL程式同樣的錯誤訊息或行為的話,就可以放到 comp.lang.c++ 了, 
   其他系統的 C++程式員可能幫得上忙。 
 
2. 「信件標題」欄位要有意義。像是「C++ 程式」這樣的標題太空泛了,「new 一 
   個多維陣列的問題」就很好。不要用一堆驚歎號,窮嚷嚷著「救命啊」,或是開 
   玩笑的用「SEX SEX SEX」這種標題。如果你認為該問題和你的編譯器有關,最好 
   在標題欄中道出編譯器和版本編號。 
 
3. 列出完整的、可編譯得過去的程式碼。要從人類的語言敘述裡,去除錯或是重建 
   回一個程式,是極為困難的事。「完整的程式碼」指的是:任何被用到的型別、 
   函式都要宣告出來,被用到的標頭檔都要 #include 進來……等等。請將程式碼 
   裁減到只留必要的部份,我們並不需要那些執行起來(甚至連結時)“有用的” 
   東西,我們只須能重現出你的錯誤訊息(可能在不同的編譯器中)就行了。「可 
   編譯得過去」指的是:不要含有一堆未註解掉的 ... 這種刪節號,或是各行行首 
   的行號: 
 
        14:     #include  
        15:     class Foo { ... };  // 像這樣就是很討人厭的東西! 
 
   將你的程式組織成線性結構,不要讓我們再切割、製造些標頭檔案。請仔細輸入 
   你的程式碼--我們通常不容易判斷:某個地方只是你的打字錯誤,抑或它真的 
   就是你的問題所在。儘量改用編輯器的「剪貼」或「插入檔案」功能。 
 
4. 列出你用的編譯器、編譯器版本,以及你使用的系統。我知道我剛剛說過:特定 
   系統的問題要去特定的信區發問,但和編譯器有關的資訊,常常對偵查問題有幫 
   助(「喔,我記得 Acme 1.2 在這方面有很多毛病」),這也順便提醒了那些編 
   譯器的使用者:小心那些毛病。 
 
5. 把編譯器、連結器的選項寫出來,以及你用來建程式所用的程式庫。 
 
6. 把錯誤訊息和何處發生錯誤的資料寫出來。像是「虛擬函式不能用了」並沒告訴 
   我們這是個編譯時段、連結時段還是執行期的問題。如果這問題是執行期發生的 
   ,請把它的行為,和任何相關的系統設定資訊列出來。 
 
7. 在簽名檔中列出真的能用的 e-mail 地址。如果你信件的 "From:" 一欄有錯的話 
   ,請通知你的者。在它修復前,於你的信件標頭中加入 "Reply-To:" 一 
   欄,填上你正確的 e-mail 地址。 
 
8. 請讀讀這份 FAQ 的其他部份--可能你的問題,或是很相關的問題就在這兒。 
 
   謝謝您,並希望以上的建議能協助您找到問題的解答。 
 
 
=================================== 
■□ 第3節:周遭的、管理上的事項 
=================================== 
 
Q3:什麼是 OOP?什麼是 C++? 
 
物件導向(OO)程式技術,是我們所知發展大型而複雜的軟體系統最好的方法。 
 
C++ 是個物件導向的程式語言。C++ 可當成一個物件導向程式語言(OOPL),亦可只 
當成一個“更好的 C 語言”來使用。不過,若你只把它當成“更好的 C”,你就無 
法獲得物件導向程式設計的好處。 
 
提一則 OO 的廣告詞:軟體工業刻正無法應付大型而複雜的軟體系統需求。但這正是 
肇因於我們的「成果」:我們過去的成功促使大家要求得更多,不幸的是,這份市場 
的渴求卻是「結構化」分析(analysis)、設計(design)和程式設計所無法滿足的 
。因此,我們才得發展一個更好的典□(paradigm)。 
 
======================================== 
 
Q4:C++ 的優點是什麼? 
 
「C++ 的成長」:C++ 是到目前為止最受歡迎的語言。每 7.5到 9個月 C++的使用者 
都會加倍。「懂 C++」是個很好的求職資格(但你必須把它當成 OOPL,而不只是一 
個更好的 C 來用才行)。 
 
「封裝性 encapsulation」:藉由隱藏內部的資料結構,讓我們可以改變系統的某部 
份,而不必更動其他部份。我們為軟體元件(稱之為 class,類別)提供一個的 
介面,使用者只碰得到這個介面而已;而相對起來比較容易變動的介面「實作」部份, 
就被封裝起來(就像被包在膠囊裡),以避免使用者過於依賴他一時的實作決定。在比 
較簡單的 C 裡頭,可由模組內的靜態(static)資料來辦到,以避免其他模組存取 
到它。 
 
「多重案例 multiple instances」:典型的 C 語言「封裝」方法(剛才有提),做 
不到多重的資料案例(我們很難替模組的 "static" 資料做出多重案例)。如果在 C 
中要做到的話,我們得使用 "struct" 結構(但是它沒有「封裝性」)。在 C++裡, 
我們可用 "class"(物件類別)來做到多重案例與封裝性:"public"公共部份包含了 
它的介面(通常這裡會有個特別的函式:成員函式),"private" 私有部份包含了它 
的實作細節(通常這兒就是內部資料結構的所在)。 
 
「行內函式呼叫」:在 C 中,可以在 struct 裡放個 "void*"(該存取函式 [access 
functions] 會用到指標轉型)來達到「封裝的 structs」。這樣會喪失型別安全性 
,而且會造成過多的函式呼叫,即使你只存取結構內的小小欄位(假如你允許直接存 
取結構內欄位的話,它內部的資料結構就很難再變更了,因為你的程式有太多地方“ 
依賴”它以前的樣子)。函式呼叫的額外負擔不大,但是會累積起來。C++ 的類別允 
許函式作 "inline" 行內擴充套件,就有以下好處:□封裝的安全性,□多重案例的方便 
性,□直接存取的速度。而且,編譯器也會檢查行內函式的引數,這就比 C 的 
#define 巨集更好了。 
 
「多載運運算元」:C++ 能對物件類別的運運算元加以多載(overload),以合乎我們的 
直覺(譬如,"myString + yourString" 可做字串串接,"myDate++"可用來遞增日期 
,"z1 * z2" 可將兩複數 z1 及 z2 相乘,"a[i]" 可用來存取 "a" 這個連結串列的 
第 i 個元素……等等)。你甚至可以做出個“聰明的指標”(smart pointer),以指 
向磁碟或其他地方去("x = *p" 可 dereference [解參用] 指標,也就可以在磁碟 
中找到 p 所“指到”的地方,並傳回其值)。這可讓使用者以切近該問題的方式來 
寫程式,而非以機器的語言來解題。 
 
  【譯註】STL (Standard Template Library) 就大量利用到「聰明的指標」功能。 
 
「繼承性 inheritance」:我們還只是在表層而已,事實上,我們還沒進入「物件導 
向」的部份呢!假設你有個 Stack 堆疊型態,有 push、pop 運算。若你還想要個 
InvertableStack 型態,它“很像”Stack,只是它還有個 "invert" 運算。以 C 的 
方式,你不是得□修改現存的 Stack模組(如果它在其他地方也用到的話,就麻煩了 
),就是得□把 Stack複製到另一個檔案,再加以修改之(這會導致過多重複的程式 
碼、容易破壞到 InvertableStack 裡某些源自 Stack 的小地方,尤有甚者,得維護 
雙倍的程式碼)。C++提供了更乾淨的解決法:繼承。你可以說:「InvertableStack 
繼承了 Stack的一切,且 InvertableStack又新增了 invert 運算。」這樣子就好了 
!Stack本身仍然是封閉的(未被更動到),而 InvertableStack也沒重複 push/pop 
等的程式碼。 
 
「多型」與「動態繫結」:OOP 真正的力量不僅是繼承性,還有把 InvertableStack 
當成是一個 Stack來傳遞的能力。這是安全的,因為(至少在 C++裡)此乃「是一個 
……」的關係("is-a" relation),透過公共繼承達到的(亦即:InvertableStack 
“是一個”Stack,且它還能自我 invert 反轉)。多型(polymorphism)與動態系 
結(dynamic binding)最容易從例項來理解了,所以我提個典型的例子:繪圖軟體 
得處理圓形、方形、矩形、多邊形及直線,這些都是「形狀 shape」。大部份繪圖軟 
體的內部函式都需要個“形狀”的引數(相對於某些像是“方形”這種特定的形狀) 
,譬如:當我們用滑鼠選取某個圖形,它就可能被拖曳放到螢幕某處。多型和動態系 
結讓程式能正確運作,即使編譯器只知道該引數是個「形狀」,而不知它到底是什麼 
形狀。我們再假設剛才提到的 "pick_and_drag(Shape*)" 函式於星期二編譯好了, 
到了星期三,你打算再加個六邊形。聽起來很奇怪,但 pick_and_drag() 仍然能夠 
處理這個六邊形,即使當 pick_and_drag() 編譯時六邊形還不存在!(若你明瞭 
C++ 是怎麼做的,它就再也不驚異了--但它仍然是很方便的!) 
 
======================================== 
 
Q5:誰在用 C++? 
 
很多很多的公司及政府部門。相當的多。 
 
統計上來看:當你正在讀這份 FAQ文字時,就有 5 個人正成為 C++的程式員。 
 
======================================== 
 
Q6:有任何 C++ 標準化方案在進行嗎? 
 
有的;ANSI(美國的)和 ISO(國際的)組織正密切合作。ANSI-C++ 委員會稱為 
"X3J16" ,而 ISO C++ 標準團體稱為 "WG21"。ANSI/ISO C++ 的標準過程中包含了 
這些人: 
 
AT&T, IBM, DEC, HP, Sun, MS, Borland, Zortech, Apple, O 等等等等。每次開 
會約有 70 人,他們來自美、英、日、德、瑞典、丹麥、法國……(他們都有「區域 
性」的委員會,派遣正式代表並主導「區域性」的會議)。 
 
======================================== 
 
Q7:該到哪裡索取最新的 ANSI-C++ 標準草案? 
 
ISO Committee Draft for C++ 以及 ANSI C++ Draft(將要供 public review 的文 
件)可如此取得: 
        ~mrs/wp-draft 
 
你也可以拿到 Postscript 和 Adobe Acrobat 的版本: 
        ftp://research.att.com/dist/stdc++/WP 
 
也能拿到 HTML 和 ASCII 的版本: 
        ftp://ftp.cygnus.com/pub/g++ 
 
也能拿到書面版本: 
        X3 Secretariat 
        1250 Eye Street NW 
        Suite 200 
        Washington, DC  20005 
        202-626-5738 
 
你也可以用 email: 
 
        lbarra@itic.nw.dc.us (Lynn Barra) 
 
註明要索取最新的 "Draft Proposed American National Standard for Information 
Systems -- Programming Language C++",檔案編號 CD14882。它通常是用2日期的 
FedEx(美國境內)來遞送的,所以很快就能收到。 
 
======================================== 
 
Q8:C++ 對 ANSI-C 回溯相容嗎? 
 
幾乎是。 
 
C++ 儘可能地和 C 相容,但不能更相容了。事實上,主要的不同在於 C++ 要求函式 
原型:"f()" 宣告的是無引數的函式(在 C 裡,"f()" 和 "f(...)" 是一樣的)。 
還有些細微的差別,像在 C++ 裡 sizeof('x') 等同於 sizeof(char),但在 C 裡面 
卻是等同於 sizeof(int)。 而且,C++ 直接就把結構的標籤(tag)當成是型別的名 
字,但 C 就需要加個 "struct" 字("typedef struct Fred Fred" 這種技巧仍然能 
用,但在 C++ 中是累贅的)。 
 
======================================== 
 
Q9:多久才能學會 C++? 
 
像 Paradigm Shift 公司,成功地教授過標準的工業界「短期課程」,將大學一學期 
的課到一週 40 小時。然而真正的精通得由實際經驗而來:沒有東西能取代時間 
。需動手做的指定專題是必要的,因為它們能將你的觀念「凝固成形」。 
 
大約要 6-12 個月才能流利使用 C++/OOP,如果身邊有高手的話,費時會短些;反之 
若沒有個“好的”通用型 C++物件程式庫,則會耗時更久。想成為顧問級的高手,則 
約需 3 年。 
 
有些人卻根本辦不到。除非你是可造之材,且有強烈的個人力,否則你也做不到 
。「孺子可教」最起碼的要求是:你必須能「覺今是而昨非」。「驅動力」最起碼的 
要求是:你願意多投入時間精力(改變思考的方式〔典□轉移 paradigm shift〕要 
遠比學些新的東西來得困難)。 
 
 
========================= 
■□ 第4節:C++ 的基礎 
========================= 
 
Q10:什麼是類別(class)? 
 
物件導向系統的基石。 
 
類別是用來定義資料型態(data type)的,就像 C 的 struct 一樣。 
以資訊科學術語來說,一個型態包含了一組狀態(state),以及在狀態之間轉移的 
動作行為(operation)。因此 "int" 是個「型態」,因為它有一組狀態,還有諸如 
「加兩個整數」、「整數相乘」等等的運作行為。同樣的,「類別」提供一組(通常 
是公共的)運算,及一組(通常是非公共的)資料欄位,以代表該型態的案例所擁有 
的抽象值。以 C 的角度來看,類別就是其成員(members)皆預設為 "private" 的 
struct。 
 
把 "int" 想成是個類別,它擁有 "operator++" 等等的運作行為(method)。 
 
======================================== 
 
Q11:什麼是物件(object)? 
 
一塊賦有某種語意的儲存空間。 
 
在宣告 "int i;" 之後,我們稱「i 是個 int 型態的物件」。在 C++/OOP 裡,「物 
件」通常意指「類別的案例(an instance of a class)」,因此類別定義了數個物 
件(案例)的行為。 
 
======================================== 
 
Q12:什麼是參考(reference)? 
 
一個物件的“別名”(alias,另一個名稱)。 
 
參考通常用於傳址呼叫(pass-by-reference): 
 
        void s(int& i, int& j) 
        { 
          int tmp = i; 
          i = j; 
          j = tmp; 
        } 
 
        main() 
        { 
          int x, y; 
          //... 
          swap(x,y); 
        } 
 
在這裡 "i" 和 "j" 分別是是 main 函式中 "x" 與 "y" 的別名,換句話說,"i" 就 
是 "x"--不是個指向 "x" 的指標,也不是 "x" 該值的複製品,而它的的確確就是 
"x" 本身。你對 "i" 做的任何動作,都會反映到 "x" 上;反之亦然。 
 
從最底層來看,參考最常用指標來實作,它的效果有點像 C 裡頭的「傳指標呼叫」 
(pass-by-pointer),但 "&" 取址運運算元由呼叫者換到被呼叫者之處了,你也要刪 
去所有的 "*" 運運算元。 
 
======================================== 
 
Q13:如果設定某值給參考會怎麼樣? 
 
會更動到被參考者(referrent,該「參考」所參考到的物件)。 
 
記住:「參考」就是「被參考者」,因此動了參考就會改動到被參考者(「參考」是 
「被參考者」的左值 "Lvalue"〔出現在設定陳述的左邊〕)。 
 
更進一步,我們也允許參考被傳回。這樣子函式呼叫就可放在設定陳述的左邊,這對 
運運算元多載的場合很有用。 
 
======================================== 
 
Q14:怎樣才能將參考改設成別的物件? 
 
沒有辦法。 
 
和指標不同,一旦參考被繫結到某個物件,它就不能再被改設到其他物件去。「參考 
」本身不是一個物件(它自己沒有位址;「取參考的位址」只會得到被參考者的位址 
;切記:「參考」就是「被參考者」)。 
 
將「參考」與「被參考者」分離開來是不可能的。 
 
======================================== 
 
Q15:何時該用參考,何時又該用指標? 
 
可以時,用參考;必要時,就用指標。 
 
當你不需要“重設”它時(見前一個問題),參考會比指標好。這通常意味著:在物 
件類別的公共介面中參考最有用。參考大多用於物件的表層,而指標則多用於裡層。 
 
但有一個例外:當函式引數或傳回值需要一個「臨界」(sentinel)的參考值時,最 
好是用指標來做,以 NULL 指標做為一個特別值(「參考」應該是個實質物件的「別 
名」,而不是個解參用的〔dereferenced〕NULL 指標)。 
 
注意:老資格的 C 程式員不喜歡參考,因為在父程式的地方,「參考」的語意並不 
是那麼明顯。然而有了些 C++經驗後,會發現這正是一種「資訊隱藏」的作法,是利 
而非弊。好比說,程式員應該以切近該問題的方式來寫程式,而非以機器的語言來解 
題。 
 
======================================== 
 
Q16:行內函式是做什麼的? 
 
行內函式(inline function)是個程式碼會塞入呼叫者所在之處的函式。就像巨集 
一樣,行內函式免除了函式呼叫的額外負擔,以增進效率,並且(尤其是!)還能讓 
編譯器對它施以最佳化(融合 "procedural integration")。不過和巨集不同 
的是:它只會對所有引數求一次的值(在語意上,該“函式呼叫”和正常函式一樣, 
只是比較罷了),以避免某些不易察覺的巨集錯誤。此外,它還會檢測引數的型 
態,做必要的型別轉換(巨集對你有害;除非絕對必要,否則別再用它了)。 
 
注意:過度使用行內函式會讓程式碼肥胖,於分頁(paging)環境下反而有負面的性 
能影響。 
 
宣告法:在函式定義處使用 "inline" 關鍵字: 
 
        inline void f(int i, char c) { /*...*/ } 
 
或者是在類別內將定義包括進去: 
 
        class Fred { 
        public: 
          void f(int i, char c) { /*...*/ } 
        }; 
 
或是在類別外頭,以 "inline" 來定義該成員函式: 
 
        class Fred { 
        public: 
          void f(int i, char c); 
        }; 
 
        inline void Fred::f(int i, char c) { /*...*/ } 
 
 
============================= 
■□ 第5節:建構子和解構子 
============================= 
 
Q17:建構子(constructor)是做什麼的? 
 
建構子乃用來從零開始建立物件。 
 
建構子就像個「初始化函式」;它把一堆散亂的位元組成一個活生生的物件。最低限 
度它會初始化內部用到的欄位,也可能會配置所須的資源(記憶體、檔案、semaphore 
、socket 等等)。 
 
"ctor" 是建構子 constructor 最常見的縮寫。 
 
======================================== 
 
Q18:怎樣才能讓建構子呼叫另一個同處一室的建構子? 
 
沒有辦法。 
 
原因是:如果你呼叫另一個建構子,編譯器會初始化一個暫時的區域性物件;但並沒 
有初始化“這個”你想要的物件。你可以用預設引數(default parameter),將兩 
個建構子合併起來,或是在私有的 "init()" 成員函式中共享它們的程式碼。 
 
======================================== 
 
Q19:解構子(destructor)是做什麼的? 
 
解構子乃物件之葬禮。 
 
解構子是用來釋放該物件所配置到的資源,譬如:Lock 類別可能會鎖住一個 
semaphore,解構子則用來釋放它。最常見的例子是:當建構子用了 "new" 以後,解 
構子用 "delete"。 
 
解構子是個「去死吧」的運作行為(method),通常縮寫為 "dtor"。 
 
 
========================= 
■□ 第6節:運運算元多載 
========================= 
 
Q20:運運算元多載(operator overloading)是做什麼的? 
 
它可讓使用類別的人以直覺來操作之。 
 
運運算元多載讓 C/C++ 的運運算元,能對自訂的型態(物件類別)賦予自訂的意義。它 
們形同是函式呼叫的語法糖衣 (syntactic sugar): 
 
        class Fred { 
        public: 
          //... 
        }; 
 
        #if 0 
          Fred add(Fred, Fred);         //沒有運運算元多載 
          Fred mul(Fred, Fred); 
        #else 
          Fred operator+(Fred, Fred);   //有運運算元多載 
          Fred operator*(Fred, Fred); 
        #endif 
 
        Fred f(Fred a, Fred b, Fred c) 
        { 
          #if 0 
            return add(add(mul(a,b), mul(b,c)), mul(c,a));  //沒有... 
          #else 
            return a*b + b*c + c*a;                         //有... 
          #endif 
        } 
 
======================================== 
 
Q21:哪些運運算元可以/不能被多載? 
 
大部份都可以被多載。 
不能的 C 運運算元有 "." 和 "?:"(和以技術上來說,可算是運運算元的 "sizeof")。 
C++ 增加了些自己的運運算元,其中除了 "::" 和 ".*". 之外都可以被多載。 
 
底下是個足標(subscript)運運算元的例子(它會傳回一個參考)。最前面是“不用 
”多載的: 
 
        class Array { 
        public: 
          #if 0 
            int& elem(unsigned i) { if (i>99) error(); return data[i]; } 
          #else 
            int& operator[] (unsigned i) { if (i>99) error(); return data[i]; } 
          #endif 
        private: 
          int data[100]; 
        }; 
 
        main() 
        { 
          Array a; 
 
          #if 0 
            a.elem(10) = 42; 
            a.elem(12) += a.elem(13); 
          #else 
            a[10] = 42; 
            a[12] += a[13]; 
          #endif 
        } 
 
======================================== 
 
Q22:怎樣做一個 "**"「次方」運運算元? 
 
無解。 
 
運運算元的名稱、優先序、結合律以及元數(arity)都被語言所定死了。C++ 裡沒有 
"**" 運運算元,所以你無法替類別訂做一個它。 
 
還懷疑的話,考慮看看 "x ** y" 和 "x * (*y)",這兩者是完全一樣的(換句話說 
,編譯器會假設 "y" 是個指標)。此外,運運算元多載只是函式呼叫的語法糖衣而已 
,雖然甜甜的,但本質上並未增加什麼東西。我建議你多載 "pow(base,exponent)" 
這個函式(它的倍精確度版本在  中)。 
 
附帶一提:operator^ 可以用,但它的優先序及結合律不符「次方」所需。 
 
 
=================== 
■□ 第7節:夥伴 
=================== 
 
Q23:夥伴(friend)是什麼? 
 
讓別的類別或函式能存取到你的類別內部的東西。 
 
夥伴可以是函式或其他類別。類別會對它的夥伴開放存取。正常情況下,程式員 
會下意識、技術性地控制該類別的夥伴與運作行為(否則當你想更動類別時,還得先 
有其他部份的擁有者之同意才行)。 
 
======================================== 
 
Q24:「夥伴」違反了封裝性嗎? 
 
若善用之,反而會「強化」封裝性。 
 
我們經常得將一個類別切成兩半,當這兩半各有不同的案例個數及生命期時。在此情 
形之下,它們通常需要直接存取對方的內部(這兩半“本來”是在同一個類別裡面, 
所以你並未“增加”存取資料結構的運作行為個數;你只是在“搬動”這些運作行為 
所在之處而已)。最安全的實作方式,就是讓這兩半互為彼此的「夥伴」。 
 
若你如上述般的使用夥伴,你依然是將私有的東西保持在私有的狀態。遇到上述的情 
況,如果還呆呆的想避免使用夥伴關係,許多人不是採用公共資料(糟透了!),就 
是弄個公共的 get/set 存取運作行為來存取彼此的資料,事實上這些都破壞了封裝 
性。只有在類別的外面該私有資料「仍有其意義」(以使用者的角度來看)時,開放 
出私有資料的存取運作行為才稱得上是恰當的做法。多數情況下,「存取運作行為」 
就和「公共資料」一樣糟糕:它們對私有資料成員只隱其“名”而已,卻未隱藏其“ 
存在”。 
 
同樣的,如果將「夥伴函式」做為另一種類別公共存取函式的語法,那就和違反封裝 
性的成員函式一樣破壞了封裝。換句話說,物件類別的夥伴及成員都是「封裝的界線 
」,如同「類別定義」本身一樣。 
 
======================================== 
 
Q25:夥伴函式的優缺點? 
 
它提供了某種介面設計上的自由。 
 
成員函式和夥伴函式都有同等的存取特權(100% 的權利),主要的差別在於:夥伴 
函式用起來像是 "f(x)",而成員函式則是 "x.f()"。因此,夥伴函式可讓物件類別 
設計者挑選他看得最順眼的語法,以降低維護成本。 
 
夥伴函式主要的缺點在於:當你想做動態繫結(dynamic binding)時,它需要額外 
的程式碼。想做出「虛擬夥伴」的效果,該夥伴函式應該呼叫個隱藏的(通常是放在 
"protected:" 裡)虛擬成員函式;像這個樣子:"void f(Base& b) { b.do_f(); }" 
。衍生類別會覆蓋(override)掉那個隱藏的成員函式("void Derived::do_f()") 
,而不是該夥伴函式。 
 
======================================== 
 
Q26:「夥伴關係無繼承及遞移性」是什麼意思? 
 
夥伴關係的特權性無法被繼承下來:夥伴的衍生類別不必然還是夥伴(我把你當朋友 
,但這不代表我也一定會信任你的孩子)。如果 "Base" 類別宣告了 "f()" 為它的 
夥伴,"f()" 並不會自動對由 "Base" 衍生出來的 "Derived" 類別所多出來的部份 
擁有特殊的存取權力。 
 
夥伴關係的特權無遞移性:夥伴類別的夥伴不必然還是原類別的夥伴(朋友的朋友不 
一定也是朋友)。譬如,如果 "Fred" 類別宣告了 "Wilma" 類別為它的夥伴,而且 
"Wilma" 類別宣告了 "f()" 為它的夥伴,則 "f()" 不見得對 "Fred" 有特殊的存取 
權力。 
 
======================================== 
 
Q27:應該替類別宣告個成員函式,還是夥伴函式? 
 
可能的話,用成員函式;必要時,就用夥伴。 
 
有時在語法上來看,夥伴比較好(譬如:在 "Fred" 類別中,夥伴函式可把 "Fred" 
弄成是第二個引數,但在成員函式中則一定得放在第一個)。另一個好例子是:二元 
中序式算數運運算元(譬如:"aComplex + aComplex" 可能應該定義成夥伴而非成員函 
數,因為你想讓 "aFloat + aComplex" 這種寫法也能成立;回想一下:成員函式無 
法提升它左側的引數,因為那樣會把引發該成員函式的物件所屬之類別給改變掉)。 
 
在其他情況下,請選成員函式而不要用夥伴函式。 
 
 
==================================================== 
■□ 第8節:輸入/輸出: 和  
==================================================== 
 
Q28:該怎樣替 "class Fred" 提供輸出功能? 
 
用夥伴函式 operator< 
        class Fred { 
        public: 
          friend ostream& operator<            { return o <          //... 
        private: 
          int i;    //只為了說明起見而設的 
        }; 
 
我們用夥伴而不用成員函式,因為 "Fred" 是第二個引數而非第一個。輸入的功能亦 
類似,只是要改寫成: 
 
        istream& operator>> (istream& i, Fred& fred); 
                                      // ^^^^^------- 不是 "const Fred& fred"! 
 
======================================== 
 
Q29:為什麼我該用  而不是以前的 ? 
 
增加型別安全、減少錯誤、增進效率、有延展性、提供衍生能力。 
 
Printf 還好,而 scanf 除了容易寫錯之外也還算可以,然而和 C++ 的 I/O 系統相 
比,它們都有其限制。C++ 的 I/O(用 "<>" ),和 C( "printf()" 和 
"scanf()" )相比: 
 
 * 型別安全--要做 I/O 的物件,編譯器會靜態地事先得知其型別,而不是動態地 
   由 "%" 一欄查知。 
 
 * 不易出錯--冗餘的資訊會增加錯誤的機會。C++ 的 I/O 就不需要多餘的 "%"。 
 
 * 更快速--printf 是個小型語言的「解譯器」,該語言主要是由 "%" 這種東西 
   構成的;在執行期它用這些欄位來選擇正確的格式化方式。C++ 的 I/O 系統則是 
   靜態的依各引數真正的型別來挑選副程式,以增進執行效率。 
 
 * 延展性--C++ I/O 機制可在不改動原有程式碼的情況下,就加進使用者新設計 
   的型態(能想像如果大家同時把互不相容的 "%" 欄位塞入 printf 和 scanf,會 
   是怎樣的混亂場面?!)。 
 
 * 可衍生(subclassable)--ostream 和 istream(C++ 的 FILE* 代替品)都是 
   真正的類別,因此可以被衍生下去。這意味著:你可以讓其他自定的東西有著和 
   stream 雷同的外表與行為,但實際上做的卻是你想做的特定事情。你自動就

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990889/,如需轉載,請註明出處,否則將追究法律責任。

相關文章