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

            Legend

            inline virtual function

            標(biāo)準(zhǔn)C++編程:虛函數(shù)與內(nèi)聯(lián)

            Josée Lajoie and Stanley Lippman

            ------------------------------------------------------------------------------
            ----

            [This is the last installment of a column that was being published in C++ Repo
            rt magazine. Since the magazine ceased publication before this installment cou
            ld be published, Josée Lajoie and Stan Lippman were gracious enough to let us
            publish it on the CUJ website. — mb]

             

            曾經(jīng),我們常常在談及C++時(shí)聽(tīng)到一個(gè)問(wèn)題:“虛函數(shù)真的應(yīng)該被申明為內(nèi)聯(lián)嗎?”現(xiàn)在,
            我們很少再聽(tīng)到這個(gè)問(wèn)題了。反過(guò)來(lái),我們現(xiàn)在聽(tīng)到的是“你不應(yīng)該將print()函數(shù)內(nèi)聯(lián)。
            將虛函數(shù)申明為內(nèi)聯(lián)是錯(cuò)誤的。”

            這么說(shuō)有兩個(gè)主要理由:(1)虛函數(shù)是在運(yùn)行期判決的,而內(nèi)聯(lián)是編譯期行為,所以不能從
            這個(gè)(內(nèi)聯(lián))申明上得到任何好處;(2)將虛函數(shù)申明為內(nèi)聯(lián)將造成此函數(shù)在可執(zhí)行文件中
            有多份拷貝,因此我們?yōu)橐粋€(gè)無(wú)論如何都不能內(nèi)聯(lián)的函數(shù)付出了在空間上的處罰(WQ注,
            所謂的內(nèi)聯(lián)函數(shù)非內(nèi)聯(lián)問(wèn)題)。顯然沒(méi)腦子。

            只是它并不真的正確。反思一下理由(1):在很多情況下,虛函數(shù)是靜態(tài)判決的--尤其是
            派生類(lèi)的虛函數(shù)調(diào)用它的基類(lèi)版本時(shí)。為什么會(huì)那么做?封裝。一個(gè)很好的例子是析構(gòu)函
            數(shù)的靜態(tài)調(diào)用鏈:基類(lèi)的析構(gòu)函數(shù)被派生類(lèi)的析構(gòu)函數(shù)觸發(fā)。除了最初的一個(gè)外,所有的
            析構(gòu)函數(shù)的調(diào)用都是被靜態(tài)判決的。不讓基類(lèi)的虛析構(gòu)函數(shù)內(nèi)聯(lián),就不能從中獲益。這會(huì)
            造成很大的差別嗎?如果繼承層次很深,而又有大量的對(duì)象需要析構(gòu),(答案是)“是的
            ”。

            另外一個(gè)例子不涉及析構(gòu)函數(shù)。想像我們正在設(shè)計(jì)一個(gè)圖書(shū)館出借管理程序。我們已經(jīng)將
            “位置”放入抽象類(lèi)LibraryMaterial。當(dāng)申明print()函數(shù)為純虛函數(shù)時(shí),我們也提供其
            定義:打印出對(duì)象的位置。

            class LibraryMaterial {

            private:

            MaterialLocation _loc; // shared data

            // ...

             

            public:

            // declares pure virtual function

            inline virtual void print( ostream& = cout ) = 0;

            };

             

            // we actually want to encapsulate the handling of the

            // location of the material within a base class

            // LibraryMaterial print() method - we just don’t want it

            // invoked through the virtual interface. That is, it is

            // only to be invoked within a derived class print() method

             

            inline void

            LibraryMaterial::

            print( ostream &os ) { os << _loc; }

             

             

            接著引入Book類(lèi);它的print()函數(shù)會(huì)輸出書(shū)名、作者等等。在此之前,它先調(diào)用基類(lèi)的L
            ibraryMaterial::print()函數(shù)以顯示位置信息。例如:

            inline void

            Book::

            print( ostream &os )

            {

            // ok, this is resolved statically,

            // and therefore is inline expanded ...

            LibraryMaterial::print();

             

            os << "title:" << _title

            << "author" << _author << endl;

            }

            AudioBook類(lèi)從Book派生,引入了一個(gè)二選一的借出策略,并且加入了一些附加信息,比如
            講解員、格式等等。這些都將在它的print()函數(shù)中顯示出來(lái)。在顯示這些以前,它先調(diào)用
            Book::print():

             

            inline void

            AudioBook::

            print( ostream &os )

            {

            // ok, this is resolved statically,

            // and therefore is inline expanded ...

            Book::print();

            os << "narrator:" << _narrator << endl;

            }

            在這個(gè)例子和析構(gòu)函數(shù)的例子中,派生類(lèi)的虛方法遞增式地?cái)U(kuò)展其基類(lèi)版本的功能,并以
            調(diào)用鏈的方式被調(diào)用,只有最初一次調(diào)用是由虛體系決定的。這個(gè)沒(méi)有被命名的繼承樹(shù)設(shè)
            計(jì)模式,如果從不將虛函數(shù)申明為內(nèi)聯(lián)的話(huà),顯然會(huì)有些低效。

            關(guān)于理由(2)的代碼膨脹問(wèn)題怎么說(shuō)?好吧,思考一下。如果寫(xiě)出,

            LibraryMaterial *p =

            new AudioBook( "Mason & Dixon",

            "Thomas Pynchon", "Johnny Depp" );

            // ...

            p->print();

            此處的print()會(huì)內(nèi)聯(lián)嗎?不,當(dāng)然不會(huì)。這必須在運(yùn)行期經(jīng)過(guò)虛體系的判決。Okay。它會(huì)
            導(dǎo)致此處的print()函數(shù)有它自己的定義體嗎?也不會(huì)。調(diào)用被編譯為類(lèi)似于這種形式:


            // Pseudo C++ Code

            // Possible transformation of p->print()

            ( *p->_vptr[ 2 ] )( p );

            那個(gè)2是print()函數(shù)在相應(yīng)的虛函數(shù)表中的位置。因?yàn)檫@個(gè)對(duì)print()的調(diào)用是通過(guò)函數(shù)指
            針_vptr[2]進(jìn)行的,編譯器不能靜態(tài)決定被調(diào)用函數(shù)的位置,并且函數(shù)不能被內(nèi)聯(lián)。

            當(dāng)然,內(nèi)聯(lián)的虛函數(shù)print()的定義必須出現(xiàn)在可執(zhí)行文件中的某處,代碼才能正確執(zhí)行。
            也就是說(shuō),至少需要一個(gè)定義體,以便將它的地址放入虛函數(shù)表。編譯器如何決定何時(shí)產(chǎn)
            生那一個(gè)定義體的呢?一個(gè)實(shí)現(xiàn)策略是在產(chǎn)生那類(lèi)的虛函數(shù)表時(shí)同時(shí)產(chǎn)生那個(gè)定義體。這
            意味著針對(duì)為一個(gè)類(lèi)所生成的每個(gè)虛函數(shù)表實(shí)例,每個(gè)內(nèi)聯(lián)的虛函數(shù)的一個(gè)實(shí)例也被產(chǎn)生

            在可執(zhí)行文件中,為一個(gè)類(lèi)產(chǎn)生的虛函數(shù)表,實(shí)際上有多少個(gè)?啊,很好,問(wèn)得好。C++標(biāo)
            準(zhǔn)規(guī)定了虛函數(shù)在行為上的要求;但它沒(méi)有規(guī)定實(shí)現(xiàn)虛函數(shù)上的要求。既然虛函數(shù)表的存
            在不是C++標(biāo)準(zhǔn)所要求的,明顯標(biāo)準(zhǔn)也沒(méi)有進(jìn)一步要求如何處理虛函數(shù)表以及生成多少次。
            最佳的數(shù)目當(dāng)然是“一次”。例如,Stroustrup的原始cfront實(shí)現(xiàn)版本,在大部份情況下
            聰明地達(dá)成了這一點(diǎn)。 (Stan和Andy Koenig描述了其算法,發(fā)表于1990年3月,C++ Repo
            rt,“Optimizing Virtual Tables in C++ Release 2.0.”)

            此外,C++標(biāo)準(zhǔn)現(xiàn)在要求內(nèi)聯(lián)函數(shù)的行為要滿(mǎn)足好象程序中只存在一個(gè)定義體,即使這個(gè)函
            數(shù)可能被定義在不同的文件中。新的規(guī)則是說(shuō)滿(mǎn)足規(guī)定的實(shí)現(xiàn)版本,行為上應(yīng)該好象只生
            成了一個(gè)實(shí)例。一旦標(biāo)準(zhǔn)的這一點(diǎn)被廣泛采用,對(duì)內(nèi)聯(lián)函數(shù)潛在的代碼膨脹問(wèn)題的關(guān)注應(yīng)
            該消失了。

            C++社群中存在著一個(gè)沖突:教學(xué)上需要規(guī)則表現(xiàn)為簡(jiǎn)單的檢查表vs實(shí)踐中需要明智地依據(jù)
            環(huán)境而運(yùn)用規(guī)則。前者是對(duì)語(yǔ)言的復(fù)雜度的回應(yīng);后者,是對(duì)我們構(gòu)造的解決方案的復(fù)雜
            度的回應(yīng)。何時(shí)將虛函數(shù)申明為內(nèi)聯(lián)的問(wèn)題,是這種沖突的一個(gè)很好的例證。

             

            About the Authors
            Stanley Lippman was the software Technical Director for the Firebird segment o
            f Disney's Fantasia 2000. He was recently technical lead on the ToonShooter im
            age capture and playback system under Linux for DreamWorks Feature Animation a
            nd consulted with the Jet Propulsion Laboratory. He is currently IT Training P
            rogram Chair for You-niversity.com, an e-learning training company. He can be
            reached at stanleyl@you-niversity, www.you-niversity.com, and www.objectwrite.
            com.

            Josée Lajoie is currently doing her Master's degree in Computer Graphics at t
            he University Waterloo. Previously, she was a member of the C/C++ compiler dev
            elopment team at the IBM Canada Laboratory and was the chair of the core langu
            age working group for the ANSI/ISO C++ Standard Committee. She can be reached
            at jlajoie@cgl.uwaterloo.ca.

            posted on 2007-04-26 14:55 Legend 閱讀(795) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久久无码一区二区三区| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 久久国产欧美日韩精品免费| 亚洲国产精品久久久久| 久久天天躁狠狠躁夜夜av浪潮 | 精品久久久久久国产潘金莲| 精品一区二区久久久久久久网站| 亚洲成人精品久久| 合区精品久久久中文字幕一区| 亚洲AV无码1区2区久久| 91亚洲国产成人久久精品网址| 国产精品久久新婚兰兰| 久久不射电影网| 亚洲中文久久精品无码ww16| 久久精品国产免费一区| 狠狠综合久久综合88亚洲| 香蕉久久一区二区不卡无毒影院| 精品久久久中文字幕人妻| 国内精品久久久久国产盗摄| 久久综合狠狠综合久久综合88| 亚洲国产高清精品线久久| 久久国产一区二区| 亚洲精品无码久久久久sm| 亚洲а∨天堂久久精品| 狠狠色伊人久久精品综合网| 亚洲综合伊人久久大杳蕉| 欧美一级久久久久久久大片| 精品久久久久久国产91| 亚洲午夜久久久久久噜噜噜| 精品久久久久久久久久久久久久久 | 99久久国语露脸精品国产| 亚洲国产精品成人AV无码久久综合影院 | 26uuu久久五月天| 久久久久久a亚洲欧洲aⅴ| 久久久亚洲欧洲日产国码aⅴ | 一级a性色生活片久久无少妇一级婬片免费放| 久久综合给久久狠狠97色| 亚洲色大成网站www久久九| 久久婷婷国产剧情内射白浆| 国产精品99久久久久久宅男小说| 中文字幕精品无码久久久久久3D日动漫|