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

麒麟子

~~

導(dǎo)航

<2008年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

統(tǒng)計(jì)

常用鏈接

留言簿(12)

隨筆分類

隨筆檔案

Friends

WebSites

積分與排名

最新隨筆

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

c++虛函數(shù)表探究

C++中的虛函數(shù)的作用主要是實(shí)現(xiàn)了多態(tài)的機(jī)制。關(guān)于多態(tài),簡(jiǎn)而言之就是用父類型別的指針指向其子類的實(shí)例,然后通過父類的指針調(diào)用實(shí)際子類的成員函數(shù)。這種技術(shù)可以讓父類的指針有“多種形態(tài)”,這是一種泛型技術(shù)。所謂泛型技術(shù),說白了就是試圖使用不變的代碼來實(shí)現(xiàn)可變的算法。比如:模板技術(shù),RTTI技術(shù),虛函數(shù)技術(shù),要么是試圖做到在編譯時(shí)決議,要么試圖做到運(yùn)行時(shí)決議。
關(guān)于虛函數(shù)的使用方法,我在這里不做過多的闡述。大家可以看看相關(guān)的C++的書籍。在這篇文章中,我只想從虛函數(shù)的實(shí)現(xiàn)機(jī)制上面為大家 一個(gè)清晰的剖析。
當(dāng)然,相同的文章在網(wǎng)上也出現(xiàn)過一些了,但我總感覺這些文章不是很容易閱讀,大段大段的代碼,沒有圖片,沒有詳細(xì)的說明,沒有比較,沒有舉一反三。不利于學(xué)習(xí)和閱讀,所以這是我想寫下這篇文章的原因。也希望大家多給我提意見。
言歸正傳,讓我們一起進(jìn)入虛函數(shù)的世界。
虛函數(shù)表
對(duì)C++ 了解的人都應(yīng)該知道虛函數(shù)(Virtual Function)是通過一張?zhí)摵瘮?shù)表(Virtual Table)來實(shí)現(xiàn)的。簡(jiǎn)稱為V-Table。 在這個(gè)表中,主是要一個(gè)類的虛函數(shù)的地址表,這張表解決了繼承、覆蓋的問題,保證其容真實(shí)反應(yīng)實(shí)際的函數(shù)。這樣,在有虛函數(shù)的類的實(shí)例中這個(gè)表被分配在了 這個(gè)實(shí)例的內(nèi)存中,所以,當(dāng)我們用父類的指針來操作一個(gè)子類的時(shí)候,這張?zhí)摵瘮?shù)表就顯得由為重要了,它就像一個(gè)地圖一樣,指明了實(shí)際所應(yīng)該調(diào)用的函數(shù)。
這里我們著重看一下這張?zhí)摵瘮?shù)表。在C++的標(biāo)準(zhǔn)規(guī)格說明書中說到,編譯器必需要保證虛函數(shù)表的指針存在于對(duì)象實(shí)例中最前面的位置(這是為了保證正確取到虛函數(shù)的偏移量)。 這意味著我們通過對(duì)象實(shí)例的地址得到這張?zhí)摵瘮?shù)表,然后就可以遍歷其中函數(shù)指針,并調(diào)用相應(yīng)的函數(shù)。
聽我扯了那么多,我可以感覺出來你現(xiàn)在可能比以前更加暈頭轉(zhuǎn)向了。 沒關(guān)系,下面就是實(shí)際的例子,相信聰明的你一看就明白了。
假設(shè)我們有這樣的一個(gè)類:
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的實(shí)例來得到虛函數(shù)表。 下面是實(shí)際例程:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虛函數(shù)表地址:" << (int*)(&b) << endl;
cout << "虛函數(shù)表 — 第一個(gè)函數(shù)地址:" << (int*)*(int*)(&b) << endl;
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
實(shí)際運(yùn)行經(jīng)果如下:(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虛函數(shù)表地址:0012FED4
虛函數(shù)表 — 第一個(gè)函數(shù)地址:0044F148
Base::f
通過這個(gè)示例,我們可以看到,我們可以通過強(qiáng)行把&b轉(zhuǎn)成int *,取得虛函數(shù)表的地址,然后,再次取址就可以得到第一個(gè)虛函數(shù)的地址了,也就是Base::f(),這在上面的程序中得到了驗(yàn)證(把int* 強(qiáng)制轉(zhuǎn)成了函數(shù)指針)。通過這個(gè)示例,我們就可以知道如果要調(diào)用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()
這個(gè)時(shí)候你應(yīng)該懂了吧。什么?還是有點(diǎn)暈。也是,這樣的代碼看著太亂了。沒問題,讓我畫個(gè)圖解釋一下。如下所示:


注意:在上面這個(gè)圖中,我在虛函數(shù)表的最后多加了一個(gè)結(jié)點(diǎn),這是虛函數(shù)表的結(jié)束結(jié)點(diǎn),就像字符串的結(jié)束符“\0”一樣,其標(biāo)志了虛函數(shù)表的結(jié)束。這個(gè)結(jié)束標(biāo)志的值在不同的編譯器下是不同的。在WinXP+VS2003下,這個(gè)值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,這個(gè)值是如果1,表示還有下一個(gè)虛函數(shù)表,如果值是0,表示是最后一個(gè)虛函數(shù)表。
下面,我將分別說明“無覆蓋”和“有覆蓋”時(shí)的虛函數(shù)表的樣子。沒有覆蓋父類的虛函數(shù)是毫無意義的。我之所以要講述沒有覆蓋的情況,主要目的是為了給一個(gè)對(duì)比。在比較之下,我們可以更加清楚地知道其內(nèi)部的具體實(shí)現(xiàn)。
一般繼承(無虛函數(shù)覆蓋)
下面,再讓我們來看看繼承時(shí)的虛函數(shù)表是什么樣的。假設(shè)有如下所示的一個(gè)繼承關(guān)系:
 

請(qǐng)注意,在這個(gè)繼承關(guān)系中,子類沒有重載任何父類的函數(shù)。那么,在派生類的實(shí)例中,其虛函數(shù)表如下所示:
對(duì)于實(shí)例:Derive d; 的虛函數(shù)表如下:

 

 

我們可以看到下面幾點(diǎn):
1)虛函數(shù)按照其聲明順序放于表中。
2)父類的虛函數(shù)在子類的虛函數(shù)前面。
我相信聰明的你一定可以參考前面的那個(gè)程序,來編寫一段程序來驗(yàn)證。
一般繼承(有虛函數(shù)覆蓋)
覆蓋父類的虛函數(shù)是很顯然的事情,不然,虛函數(shù)就變得毫無意義。下面,我們來看一下,如果子類中有虛函數(shù)重載了父類的虛函數(shù),會(huì)是一個(gè)什么樣子?假設(shè),我們有下面這樣的一個(gè)繼承關(guān)系。

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

我們從表中可以看到下面幾點(diǎn),
1)覆蓋的f()函數(shù)被放到了虛表中原來父類虛函數(shù)的位置。
2)沒有被覆蓋的函數(shù)依舊。
這樣,我們就可以看到對(duì)于下面這樣的程序,
Base *b = new Derive();
b->f();
由b所指的內(nèi)存中的虛函數(shù)表的f()的位置已經(jīng)被Derive::f()函數(shù)地址所取代,于是在實(shí)際調(diào)用發(fā)生時(shí),是Derive::f()被調(diào)用了。這就實(shí)現(xiàn)了多態(tài)。
多重繼承(無虛函數(shù)覆蓋)
下面,再讓我們來看看多重繼承中的情況,假設(shè)有下面這樣一個(gè)類的繼承關(guān)系。注意:子類并沒有覆蓋父類的函數(shù)。


對(duì)于子類實(shí)例中的虛函數(shù)表,是下面這個(gè)樣子:

 


我們可以看到:
1) 每個(gè)父類都有自己的虛表。
2) 子類的成員函數(shù)被放到了第一個(gè)父類的表中。(所謂的第一個(gè)父類是按照聲明順序來判斷的)
這樣做就是為了解決不同的父類類型的指針指向同一個(gè)子類實(shí)例,而能夠調(diào)用到實(shí)際的函數(shù)。
多重繼承(有虛函數(shù)覆蓋)
下面我們?cè)賮砜纯矗绻l(fā)生虛函數(shù)覆蓋的情況。
下圖中,我們?cè)谧宇愔懈采w了父類的f()函數(shù)。

下面是對(duì)于子類實(shí)例中的虛函數(shù)表的圖:
 

我們可以看見,三個(gè)父類虛函數(shù)表中的f()的位置被替換成了子類的函數(shù)指針。這樣,我們就可以任一靜態(tài)類型的父類來指向子類,并調(diào)用子類的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++。這篇文章也不例外。通過上面的講述,相信我們對(duì)虛函數(shù)表有一個(gè)比較細(xì)致的了解了。水可載舟,亦可覆舟。下面,讓我們來看看我們可以用虛函數(shù)表來干點(diǎn)什么壞事吧。
一、通過父類型的指針訪問子類自己的虛函數(shù)
我們知道,子類沒有重載父類的虛函數(shù)是一件毫無意義的事情。因?yàn)槎鄳B(tài)也是要基于函數(shù)重載的。雖然在上面的圖中我們可以看到Base1的虛表中有Derive的虛函數(shù),但我們根本不可能使用下面的語句來調(diào)用子類的自有虛函數(shù):
Base1 *b1 = new Derive();
b1->f1(); //編譯出錯(cuò)
任何妄圖使用父類指針想調(diào)用子類中的未覆蓋父類的成員函數(shù)的行為都會(huì)被編譯器視為非法,所以,這樣的程序根本無法編譯通過。但在運(yùn)行時(shí),我們可以通過指針的方式訪問虛函數(shù)表來達(dá)到違反C++語義的行為。(關(guān)于這方面的嘗試,通過閱讀后面附錄的代碼,相信你可以做到這一點(diǎn))
二、訪問non-public的虛函數(shù)
另外,如果父類的虛函數(shù)是private或是protected的,但這些非public的虛函數(shù)同樣會(huì)存在于虛函數(shù)表中,所以,我們同樣可以使用訪問虛函數(shù)表的方式來訪問這些non-public的虛函數(shù),這是很容易做到的。
如:
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();
}

posted on 2009-07-24 23:52 麒麟子 閱讀(367) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Programming

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲人精品午夜在线观看| 久久五月婷婷丁香社区| 在线观看国产日韩| 99精品99| 日韩视频不卡中文| 久久久亚洲一区| 欧美亚洲在线视频| 欧美日韩精品二区| 亚洲第一精品福利| 国产综合香蕉五月婷在线| 一本一本久久a久久精品牛牛影视| 亚洲电影在线播放| 午夜精品一区二区三区在线视| av成人免费| 欧美国产免费| 亚洲高清二区| 亚洲人成在线播放网站岛国| 久久久亚洲国产天美传媒修理工| 香蕉久久精品日日躁夜夜躁| 欧美性大战久久久久久久蜜臀| 亚洲第一综合天堂另类专| 激情欧美丁香| 久久久久亚洲综合| 久久免费国产精品1| 国产日韩精品一区二区| 午夜精品视频在线观看| 午夜精品国产| 国产精品婷婷午夜在线观看| 亚洲男女毛片无遮挡| 亚洲欧美激情视频在线观看一区二区三区| 欧美欧美全黄| 99伊人成综合| 亚洲一区中文字幕在线观看| 国产精品久久久久久影视 | 久久精品国产亚洲精品 | 欧美激情影院| 亚洲精品日产精品乱码不卡| 欧美经典一区二区| 日韩视频在线一区| 亚洲免费中文字幕| 国产伦精品一区二区| 午夜精品一区二区三区在线| 久久久www成人免费毛片麻豆| 好吊一区二区三区| 美女视频黄免费的久久| 亚洲麻豆av| 欧美一区二区性| 狠狠色丁香婷婷综合久久片| 欧美成人a∨高清免费观看| 亚洲人体大胆视频| 午夜精品久久久久久久99樱桃| 国产午夜精品麻豆| 欧美va天堂在线| 亚洲老司机av| 久久国产精品毛片| 亚洲精品麻豆| 国产精品一区二区在线观看网站| 欧美一区二区播放| 亚洲激情电影中文字幕| 亚洲综合清纯丝袜自拍| 激情成人亚洲| 欧美视频中文在线看| 久久精品一区二区三区四区| 亚洲国产精品一区二区久| 欧美亚洲系列| 亚洲人成亚洲人成在线观看 | 欧美精品v日韩精品v韩国精品v| 亚洲免费观看高清完整版在线观看熊 | 狠狠色丁香婷综合久久| 欧美交受高潮1| 午夜久久资源| 亚洲欧洲日产国码二区| 欧美伊久线香蕉线新在线| 亚洲人成人一区二区三区| 国产精品日韩在线观看| 免费不卡在线观看av| 午夜性色一区二区三区免费视频| 亚洲成人在线免费| 中文日韩欧美| 亚洲第一成人在线| 国产精品大片wwwwww| 免费成人av资源网| 午夜免费日韩视频| 99热精品在线| 欧美激情区在线播放| 久久国产精品久久国产精品 | aa级大片欧美三级| 伊人成年综合电影网| 国产精品免费电影| 欧美区在线播放| 久久精品视频播放| 亚洲欧美日韩一区二区三区在线观看| 欧美黄色免费| 蜜臀99久久精品久久久久久软件| 亚洲与欧洲av电影| 一本色道久久综合亚洲精品婷婷| 在线免费高清一区二区三区| 国产婷婷精品| 国产精品一区二区三区免费观看| 欧美日韩国产综合视频在线观看中文 | 美女网站久久| 老巨人导航500精品| 欧美在线二区| 久久xxxx精品视频| 亚洲在线观看视频| 在线一区二区视频| 一本到高清视频免费精品| 亚洲精品在线免费观看视频| 亚洲国产一区在线| 亚洲国产三级在线| 亚洲精品久久久久久久久| 亚洲国产精品热久久| 亚洲高清毛片| 亚洲日本激情| 亚洲精品一区二区三区蜜桃久| 欧美激情一区二区三级高清视频| 欧美chengren| 亚洲国产一区二区三区青草影视 | 亚洲在线视频观看| 欧美一级理论性理论a| 亚洲欧美久久久| 午夜精品久久久久久| 久久爱www| 浪潮色综合久久天堂| 欧美激情一二三区| 欧美日韩一区二区三区在线看 | 国产精品成人播放| 国产精品丝袜久久久久久app| 国产精品影院在线观看| 好吊色欧美一区二区三区视频| 黄色亚洲大片免费在线观看| 黄色一区二区三区四区| 亚洲国产精品999| 日韩视频在线免费观看| 亚洲综合欧美| 久久一区视频| 亚洲人成网站色ww在线| 一区二区三区高清不卡| 亚洲欧美一区二区三区极速播放 | 亚洲裸体在线观看| 亚洲女性裸体视频| 久久女同精品一区二区| 欧美日韩高清区| 国产一级久久| 亚洲理论在线观看| 欧美一区二区三区电影在线观看| 麻豆精品在线视频| 一本色道久久综合亚洲二区三区| 欧美中文字幕精品| 欧美精品九九99久久| 国产午夜精品全部视频在线播放| 亚洲破处大片| 久久国产主播精品| 亚洲日韩视频| 久久激情五月丁香伊人| 欧美三级视频在线播放| 狠狠色综合播放一区二区| 中国成人亚色综合网站| 欧美 日韩 国产 一区| 亚洲一区二区三区在线视频| 久久久人人人| 国产精品久久久久久久9999| 亚洲国产高清自拍| 久久高清免费观看| 亚洲美女在线观看| 美女黄网久久| 国产一区二区精品在线观看| 一区二区三区视频在线看| 老牛嫩草一区二区三区日本| 亚洲色图综合久久| 欧美精品网站| 亚洲国内自拍| 久久综合九色| 欧美一区不卡| 国产精品自拍三区| 亚洲一区三区在线观看| 亚洲人被黑人高潮完整版| 久久久91精品国产一区二区三区| 国产精品成人一区| 一区二区三区不卡视频在线观看 | 午夜欧美大片免费观看| 欧美日韩妖精视频| 亚洲精品日韩在线观看| 欧美高清视频www夜色资源网| 欧美一区二区视频97| 国产精品久久一区二区三区| 亚洲网站在线观看| 亚洲精品久久久蜜桃| 欧美电影美腿模特1979在线看 | 亚洲制服av| 夜夜嗨av一区二区三区网站四季av| 免费不卡亚洲欧美| 亚洲欧洲日本专区| 欧美高潮视频| 欧美韩日一区二区| 亚洲乱码一区二区| 亚洲精品国精品久久99热一| 欧美黄污视频| 中国日韩欧美久久久久久久久| 亚洲美女视频在线免费观看|