• <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>
            C++分析研究  
            C++
            日歷
            <2013年3月>
            242526272812
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456
            統(tǒng)計(jì)
            • 隨筆 - 92
            • 文章 - 4
            • 評(píng)論 - 4
            • 引用 - 0

            導(dǎo)航

            常用鏈接

            留言簿

            隨筆檔案

            文章檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

             
              我們?cè)?jīng)在討論C++的時(shí)候,經(jīng)常會(huì)問(wèn)到:“虛函數(shù)能被聲明為內(nèi)聯(lián)嗎?”現(xiàn)在,我們幾乎聽(tīng)不到這個(gè)問(wèn)題了。現(xiàn)在聽(tīng)到的是:“你不應(yīng)該使print成為內(nèi)聯(lián)的。聲明一個(gè)虛函數(shù)為內(nèi)聯(lián)是錯(cuò)誤的!”

              這種說(shuō)法的兩個(gè)主要的原因是(1)虛函數(shù)是在運(yùn)行期決議而內(nèi)聯(lián)是一個(gè)編譯期動(dòng)作,所以,我們將虛函數(shù)聲明為內(nèi)聯(lián)并得不到什么效果;(2)聲明一個(gè)虛函數(shù)為內(nèi)聯(lián)導(dǎo)致了函數(shù)的多分拷貝,而且我們?yōu)橐粋€(gè)不應(yīng)該在任何時(shí)候內(nèi)聯(lián)的函數(shù)白白花費(fèi)了存儲(chǔ)空間。這樣做很沒(méi)腦子。 www.601456.com

              不過(guò),事實(shí)并不是這樣。我們先來(lái)看看第一個(gè):許多情況下,虛擬函數(shù)都被靜態(tài)地決議了——比如在派生類虛擬函數(shù)中調(diào)用基類的虛擬函數(shù)的時(shí)候。為什么這樣做呢?封裝。一個(gè)比較明顯的例子就是派生類析構(gòu)函數(shù)調(diào)用鏈。所有的虛析構(gòu)函數(shù),除了最初觸發(fā)這個(gè)析構(gòu)鏈的虛析構(gòu)函數(shù),都被靜態(tài)的決議了。如果不將基類的虛析構(gòu)函數(shù)內(nèi)聯(lián),我們無(wú)法從中獲利[a]。這和不內(nèi)聯(lián)一個(gè)虛擬析構(gòu)函數(shù)有什么不同嗎?如果繼承體系層次比較深并且有許多這樣的類的實(shí)例要被銷毀的話,答案是肯定的。

              再來(lái)看另外一個(gè)不用析構(gòu)函數(shù)的例子,想象一下設(shè)計(jì)一個(gè)圖書館類。我們將MaterialLocation作為抽象類LibraryMaterial的一個(gè)成員。將它的print成員函數(shù)聲明為一個(gè)純虛函數(shù),并且提供函數(shù)定義:它輸出MaterialLocation。

              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; }

              接著,我們引入一個(gè)Book類,它的print函數(shù)輸出Title, Author等等。在這之前,它調(diào)用基類的print函數(shù)(LibraryMaterial::print())來(lái)顯示書本位置(MaterialLocation)。如下:

              inline void

              Book:: www.liuhebao.com

              print( ostream &os )

              {

              // ok, this is resolved statically,

              // and therefore is inline expanded ...

              LibraryMaterial::print();

              os <<"title:" <<_title

              << "author" <<_author < www.szfuao.com

              AudioBook類,派生于Book類,并加入附加信息,比如旁述,音頻格式等等。這些東西都用它的print函數(shù)輸出。再這之前,我們需要調(diào)用Book::print()來(lái)顯示前面的信息。

              inline void

              AudioBook::

              print( ostream &os )

              {

              // ok, this is resolved statically,

              // and therefore is inline expanded ...

              Book::print(); www.yzjxsp.com

              os <<"narrator:" <<_narrator <

              }

              這和虛析構(gòu)函數(shù)調(diào)用鏈的例子一樣,都只是最初調(diào)用的虛函數(shù)沒(méi)有被靜態(tài)決議,其它的都被原地展開(kāi)。This unnamed hierarchical design pattern is significantly less effective if we never declare a virtual function to be inline.

              那么對(duì)于第二個(gè)原因中代碼膨脹的問(wèn)題呢?我們來(lái)分析一下,如果我們寫下:

              LibraryMaterial *p =

              new AudioBook( "Mason &Dixon",

              "Thomas Pynchon", "Johnny Depp" );

              // ...

              p->print();

              這個(gè)print實(shí)例是內(nèi)聯(lián)的嗎?不,當(dāng)然不是。這樣不得不通過(guò)虛擬機(jī)制在運(yùn)行期決議。這讓print實(shí)例放棄了對(duì)它的內(nèi)聯(lián)聲明了嗎?也不是。這個(gè)調(diào)用轉(zhuǎn)換為下面的形式(偽代碼):

              // Pseudo C++Code www.yzsws.com

              // Possible transformation of p->print()

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

              where 2 represents the location of print within the associated virtual function table.因?yàn)檎{(diào)用print是通過(guò)函數(shù)指針_vptr[2]進(jìn)行的,所以,編譯器不能靜態(tài)的決定這個(gè)調(diào)用地址,并且,這個(gè)函數(shù)也不能內(nèi)聯(lián)。

              當(dāng)然,虛函數(shù)print的內(nèi)聯(lián)實(shí)體(definition)也必須在某個(gè)地方表現(xiàn)出來(lái)。 即是說(shuō),至少有一個(gè)函數(shù)實(shí)體是在virtual table調(diào)用的地址原地展開(kāi)的。編譯器是如何決定在何時(shí)展開(kāi)這個(gè)函數(shù)實(shí)體呢?其中一個(gè)編譯(implementaion)策略是當(dāng)virtual table生成的同時(shí),生成這個(gè)函數(shù)實(shí)體。這就是說(shuō)對(duì)于每一個(gè)派生類的virtual table都會(huì)生成一個(gè)函數(shù)實(shí)體。

              在一個(gè)可應(yīng)用的類[b]中有多少vitrual table會(huì)被生成呢?呵呵,這是一個(gè)好問(wèn)題。C++標(biāo)準(zhǔn)中對(duì)虛函數(shù)行為進(jìn)行了規(guī)定,但是沒(méi)有對(duì)函數(shù)實(shí)現(xiàn)進(jìn)行規(guī)定。由于virtual table沒(méi)有在C++標(biāo)準(zhǔn)中進(jìn)行規(guī)定,很明顯,究竟這個(gè)virtual table怎樣生成,和究竟要生成多少個(gè)vitrual table也沒(méi)有規(guī)定。多少個(gè)?當(dāng)然,我們只要一個(gè)。Stroustrup的cfront編譯器,很巧妙的處理了這些情況.( Stan and Andy Koenig described the algorithm in the March 1990 C++ Report article, "Optimizing Virtual Tables in C++ Release 2.0.")

              Moreover, the C++ Standard now requires that inline functions behave as though only one definition for an inline function exists in the program even though the function may be defined in different files。新的規(guī)則要求編譯器只展開(kāi)一個(gè)內(nèi)聯(lián)虛函數(shù)。如果一點(diǎn)被廣泛采用的話,虛函數(shù)的內(nèi)聯(lián)導(dǎo)致的代碼膨脹問(wèn)題就會(huì)消失。 www.yzyedu.com

              [譯注:C++ Standard: 9.3.8, Member function of local class shall be defined inline in their class defination, if they are defined at all]

              ============================

              譯注:

              [a]函數(shù)調(diào)用開(kāi)銷,調(diào)用基類虛函數(shù)的時(shí)候至少要經(jīng)過(guò)兩次間接過(guò)程(S. B.Lippman: 《Inside the C++ Object Model》)

              [b]一個(gè)產(chǎn)品類(?)

              總結(jié):

              就是虛函數(shù)inline在調(diào)用鏈等地方很有用~

              即使沒(méi)有加入inline聲明,作為一個(gè)好編譯器,都會(huì)優(yōu)化(虛析構(gòu)函數(shù))

              在很長(zhǎng)的函數(shù)調(diào)用鏈中,最好將鏈中基類的函數(shù)inline,這樣節(jié)約開(kāi)銷

              至于在什么地方inline,由編譯器決定,因?yàn)镃++標(biāo)準(zhǔn)沒(méi)有規(guī)定

              新C++標(biāo)準(zhǔn)(可能沒(méi)有通過(guò))中,規(guī)定了,inline化只對(duì)產(chǎn)品類有效,且只動(dòng)作一次

              保證代碼不過(guò)度膨脹

              inline動(dòng)作是在產(chǎn)品類實(shí)例化同時(shí),和vtable生成一起
            posted on 2011-02-20 23:41 HAOSOLA 閱讀(186) 評(píng)論(0)  編輯 收藏 引用

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


             
            Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
            PK10開(kāi)獎(jiǎng) PK10開(kāi)獎(jiǎng)
            狠狠精品久久久无码中文字幕 | 久久久久久综合一区中文字幕| 97精品依人久久久大香线蕉97 | 国产精品一区二区久久| 久久综合丝袜日本网| 人妻无码精品久久亚瑟影视| 久久婷婷色综合一区二区| 人妻少妇久久中文字幕| 久久久久国产| 国产一区二区三区久久| 久久午夜无码鲁丝片秋霞| 久久国产乱子精品免费女| 三级片免费观看久久| 精品久久香蕉国产线看观看亚洲| 免费精品久久久久久中文字幕| 久久精品aⅴ无码中文字字幕重口| 精品乱码久久久久久夜夜嗨| 久久久久99精品成人片欧美| 久久久久久青草大香综合精品| 国产精品久久亚洲不卡动漫| 影音先锋女人AV鲁色资源网久久 | 国产精品免费看久久久| 久久久久久毛片免费看| 精品久久香蕉国产线看观看亚洲| 伊人久久大香线蕉亚洲五月天| 色综合久久久久综合99| 亚洲国产精品一区二区久久| 久久99精品久久久久子伦| 久久久亚洲AV波多野结衣| 青青草原综合久久大伊人导航| 久久AAAA片一区二区| 久久精品免费一区二区三区| 国产精品一久久香蕉国产线看观看| 国产精品久久久久久五月尺| 一本大道久久东京热无码AV | 久久婷婷五月综合色奶水99啪| 久久国产成人精品国产成人亚洲| 国产精品99久久精品爆乳| 久久99精品国产麻豆婷婷| 久久成人永久免费播放| 久久久久无码精品国产app|