西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)VC|VC++ → C++中的虛函數(shù)總結(jié)

C++中的虛函數(shù)總結(jié)

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2013/11/17 9:57:29字體大小:A-A+

作者:西西點(diǎn)擊:145次評(píng)論:2次標(biāo)簽: 虛函數(shù)

對(duì)C++ 了解的人都應(yīng)該知道虛函數(shù)(Virtual Function)是通過(guò)一張?zhí)摵瘮?shù)表(Virtual Table)來(lái)實(shí)現(xiàn)的。簡(jiǎn)稱為V-Table。 在這個(gè)表中,主是要一個(gè)類(lèi)的虛函數(shù)的地址表,這張表解決了繼承、覆蓋的問(wèn)題,保證其容真實(shí)反應(yīng)實(shí)際的函數(shù)。這樣,在有虛函數(shù)的類(lèi)的實(shí)例中這個(gè)表被分配在了 這個(gè)實(shí)例的內(nèi)存中,所以,當(dāng)我們用父類(lèi)的指針來(lái)操作一個(gè)子類(lèi)的時(shí)候,這張?zhí)摵瘮?shù)表就顯得由為重要了,它就像一個(gè)地圖一樣,指明了實(shí)際所應(yīng)該調(diào)用的函數(shù)。

一、什么是虛函數(shù)、純虛函數(shù)、抽象基類(lèi)

虛函數(shù):在某基類(lèi)中聲明為 virtual 并在一個(gè)或多個(gè)派生類(lèi)中被重新定 義的成員函數(shù)。

純虛函數(shù):是一種特殊的虛函數(shù),使用virtual關(guān)鍵字,并且在其后面加上=0。

抽象基類(lèi):在基類(lèi)中加入至少一個(gè)純虛函數(shù),使基類(lèi)成為抽象類(lèi)。

二、為什么要使用虛函數(shù)

在理解這個(gè)問(wèn)題前,就必須要理解什么是晚捆綁。

晚捆綁是相對(duì)于早捆綁而言的,那么什么又是捆綁呢?把函數(shù)體與函數(shù)調(diào)用相聯(lián)系稱為捆綁,當(dāng)捆綁在程序運(yùn)行之前完成時(shí),這稱為早捆綁。那么當(dāng)捆綁根據(jù)對(duì)象的類(lèi)型,發(fā)生在運(yùn)行時(shí),就稱為晚捆綁。

而使用晚捆綁,無(wú)需檢查對(duì)象的類(lèi)型,只需要檢查對(duì)象是否支持特性和方法即可。

為了引發(fā)晚捆綁,C++要求在基類(lèi)中聲明這個(gè)函數(shù)時(shí)使用virture關(guān)鍵字。晚捆綁只對(duì)virtual函數(shù)起作用,而且只在使用含有virtual函數(shù)的基類(lèi)的地址時(shí)發(fā)生。

三、關(guān)于重寫(xiě)

如果一個(gè)函數(shù)在基類(lèi)中被聲明為virtual,那么在所有的派生類(lèi)中它都是virtual,在派生類(lèi)中virtual函數(shù)的重定義通常稱為重寫(xiě)。

四、在C++中如何實(shí)現(xiàn)晚捆綁

虛函數(shù)主要有兩個(gè)步驟:

1、每一個(gè)類(lèi)產(chǎn)生出一堆指向虛函數(shù)的指針,放在表格中。這個(gè)表格被稱為virtual table(vtbl)

2、每一個(gè)類(lèi)對(duì)象被安插一個(gè)指針,指向相關(guān)的virtual table,通常這個(gè)指針被稱為vptr

結(jié)構(gòu)圖如下:

每當(dāng)創(chuàng)建一個(gè)包含有虛函數(shù)的類(lèi)或從包含有虛函數(shù)的類(lèi)派生一個(gè)類(lèi)時(shí),編譯器就為這個(gè)類(lèi)創(chuàng)建一個(gè)唯一的vtbl。如果在這個(gè)派生類(lèi)中沒(méi)有對(duì)在基類(lèi)中聲明為virtual的函數(shù)進(jìn)行重新定義,編譯器就使用基類(lèi)的這個(gè)虛函數(shù)地址。然后編譯器在這個(gè)類(lèi)中放置vptr。當(dāng)使用簡(jiǎn)單繼承時(shí),對(duì)于每個(gè)對(duì)象都只有一個(gè)vtbl。vptr必須被初始化為指向相應(yīng)的vtbl的起始地址。

五、虛函數(shù)的存放類(lèi)型信息

假如沒(méi)有虛函數(shù),那么對(duì)象的長(zhǎng)度就是所期望的長(zhǎng)度:比如當(dāng)個(gè)int的長(zhǎng)度。而帶有單個(gè)虛函數(shù)的One Virtual,對(duì)象的長(zhǎng)度是No Virtual的長(zhǎng)度加上一個(gè)void指針的長(zhǎng)度。如果有一個(gè)或多個(gè)虛函數(shù),編譯器都只在這個(gè)結(jié)構(gòu)中插入一個(gè)單個(gè)指針,這個(gè)指針指向虛函數(shù)表。在32為的機(jī)器上,一個(gè)指針占3字節(jié)的空間,因此求sizeof得到4;如果是64位的機(jī)器,一個(gè)指針占8字節(jié)的空間,因此求sizeof則得到8.

六、關(guān)于抽象類(lèi)和純虛函數(shù)

1、當(dāng)繼承一個(gè)抽象類(lèi)時(shí),必須實(shí)現(xiàn)所有的純虛函數(shù),否則繼承出的類(lèi)也將是一個(gè)抽象類(lèi)

2、聲明一個(gè)純虛函數(shù),就等于告訴編譯器在vtbl中為函數(shù)保留一個(gè)位置,但在這個(gè)位置不放地址。只要有一個(gè)函數(shù)在類(lèi)中被聲明為純虛函數(shù),則vtbl就是不完全的。

3、純虛函數(shù)禁止對(duì)抽象類(lèi)的函數(shù)以傳值方式調(diào)用,這是一種防止對(duì)象切片的方法。抽象類(lèi)可以保證在向上類(lèi)型轉(zhuǎn)換期間總是使用指針或引用。

4、對(duì)于純虛函數(shù),如果要?jiǎng)?chuàng)建對(duì)象,必須要在派生類(lèi)中定義。

七、什么是對(duì)象切片

在繼承的過(guò)程中,通常派生類(lèi)不僅具有基類(lèi)的特征,也具有自身的一些特征。當(dāng)派生類(lèi)向上進(jìn)行類(lèi)型轉(zhuǎn)換稱為基類(lèi)時(shí),就會(huì)發(fā)生那些自身的特征被切除,只保留繼承了基類(lèi)的特征,這種現(xiàn)象就是對(duì)象切片。

例如:狗類(lèi)繼承了寵物類(lèi),具有寵物類(lèi)的名稱這個(gè)屬性,同時(shí)又有啃骨頭的特性,當(dāng)狗類(lèi)要被轉(zhuǎn)換為寵物類(lèi)時(shí),就必須拋棄自己愛(ài)啃骨頭的愛(ài)好,這樣只保留了對(duì)應(yīng)于寵物類(lèi)的那部分。流程如下:

八、虛函數(shù)和構(gòu)造函數(shù)

1、由于基類(lèi)構(gòu)造函數(shù)總是在繼承類(lèi)構(gòu)造函數(shù)中被調(diào)用,這就確保了在派生類(lèi)中,基類(lèi)的所有成員都是有效的,即所有成員都已經(jīng)建立。

2、虛機(jī)制在構(gòu)造函數(shù)中不工作。有兩種理由:

   A、在任何構(gòu)造函數(shù)中,我們只能知道基類(lèi)已被初始化,但不能知道哪個(gè)類(lèi)是從這個(gè)基類(lèi)繼承來(lái)的。但是,虛函數(shù)在繼承層次上是向前和向后調(diào)用。它可以調(diào)用派生類(lèi)中的函數(shù)。

   B、構(gòu)造函數(shù)的vptr的狀態(tài)是由最后調(diào)用的構(gòu)造函數(shù)確定的,這就意味著當(dāng)最后調(diào)用的構(gòu)造函數(shù)還沒(méi)有完成之前,當(dāng)前的構(gòu)造函數(shù)完全不知道這個(gè)對(duì)象是否是基于其他類(lèi)的。但是,當(dāng)這一系列的構(gòu)造函數(shù)調(diào)用正發(fā)生時(shí),每個(gè)構(gòu)造函數(shù)都已經(jīng)設(shè)置vptr指向它自己的vtbl,如果函數(shù)調(diào)用使用虛機(jī)制,它將只產(chǎn)生通過(guò)它自己的vtbl的調(diào)用,而不是最后派生的vtbl。

九、虛析構(gòu)函數(shù)和析構(gòu)函數(shù)

1、析構(gòu)函數(shù)自最晚派生的類(lèi)開(kāi)始,并向上到基類(lèi)。這就意味著每個(gè)析構(gòu)函數(shù)知道它所在類(lèi)從哪一個(gè)類(lèi)派生而來(lái),但不知道從它派生出哪些類(lèi)。

2、析構(gòu)函數(shù)可以為虛函數(shù),因?yàn)檫@個(gè)對(duì)象已經(jīng)知道它是什么類(lèi)型,但是在構(gòu)造期間就不知道了。一旦對(duì)象已被構(gòu)造,它的vptr就已經(jīng)被初始化,所以能發(fā)生虛函數(shù)調(diào)用。

3、虛構(gòu)函數(shù)的純虛性的唯一效果是阻止基類(lèi)的實(shí)例化

十、虛函數(shù)、純虛函數(shù)、抽象類(lèi)的作用

虛函數(shù)的作用:每個(gè)類(lèi)必須提供一個(gè)可以被調(diào)用的虛函數(shù),但每個(gè)類(lèi)可以按它們認(rèn)為合適的任何方式處理。如果某個(gè)類(lèi)不想做什么特別的事,可以借助于基類(lèi)中提供的缺省處理函數(shù)。也就是說(shuō),虛函數(shù)的聲明是在告訴子類(lèi)的設(shè)計(jì)者,"你必須支持虛函數(shù),但如果你不想寫(xiě)自己的版本,可以借助基類(lèi)中的缺省版本。

純虛函數(shù)的作用:讓所有的類(lèi)對(duì)象(主要是派生類(lèi)對(duì)象)都可以執(zhí)行純虛函數(shù)的動(dòng)作,但類(lèi)無(wú)法為純虛函數(shù)提供一個(gè)合理的缺省實(shí)現(xiàn)。所以類(lèi)純虛函數(shù)的聲明就是在告訴子類(lèi)的設(shè)計(jì)者,“你必須提供一個(gè)純虛函數(shù)的實(shí)現(xiàn),但我不知道你會(huì)怎樣實(shí)現(xiàn)它”。

抽象類(lèi)的主要作用是將有關(guān)的操作作為結(jié)果接口組織在一個(gè)繼承層次結(jié)構(gòu)中,由它來(lái)為派生類(lèi)提供一個(gè)公共的根,派生類(lèi)將具體實(shí)現(xiàn)在其基類(lèi)中作為接口的操作。所以派生類(lèi)實(shí)際上刻畫(huà)了一組子類(lèi)的操作接口的通用語(yǔ)義,這些語(yǔ)義也傳給子類(lèi),子類(lèi)可以具體實(shí)現(xiàn)這些語(yǔ)義,也可以再將這些語(yǔ)義傳給自己的子類(lèi)。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(2)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)