C+虛函數(shù)詳解_第1頁
C+虛函數(shù)詳解_第2頁
C+虛函數(shù)詳解_第3頁
C+虛函數(shù)詳解_第4頁
C+虛函數(shù)詳解_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、虛函數(shù)必須是基類的非靜態(tài)成員函數(shù),其訪問權(quán)限可以是protected或public,在基類的類定義中定義虛函數(shù)的一般形式: virtual 函數(shù)返回值類型 虛函數(shù)名(形參表) 函數(shù)體 派生類可以重置(“覆蓋”)基類的非虛函數(shù)嗎?Effective C+有條款說明這個問題的條款37: 決不要重新定義繼承而來的非虛函數(shù)有兩種方法來看待這個問題:理論的方法和實踐的方法。讓我們先從實踐的方法開始。畢竟,理論家一般都很耐心。假設(shè)類D公有繼承于類B,并且類B中定義了一個公有成員函數(shù)mf。mf的參數(shù)和返回類型不重要,所以假設(shè)都為void。換句話說,我這么寫:class B public: void mf()

2、; .;class D: public B . ;甚至對B,D或mf一無所知,也可以定義一個類型D的對象x,D x; / x是類型D的一個對象那么,如果發(fā)現(xiàn)這么做:B *pB = &x; / 得到x的指針pB-mf(); / 通過指針調(diào)用mf和下面這么做的執(zhí)行行為不一樣:D *pD = &x; / 得到x的指針pD-mf(); / 通過指針調(diào)用mf你一定就會感到很驚奇。因為兩種情況下調(diào)用的都是對象x的成員函數(shù)mf,因為兩種情況下都是相同的函數(shù)和相同的對象,所以行為會相同,對嗎?對,會相同。但,也許不會相同。特別是,如果mf是非虛函數(shù)而D又定義了自己的mf版本,行為就不會相同:class D:

3、public B public: void mf(); / 隱藏了B:mf; 參見條款50 .;pB-mf(); / 調(diào)用B:mfpD-mf(); / 調(diào)用D:mf行為的兩面性產(chǎn)生的原因在于,象B:mf和D:mf這樣的非虛函數(shù)是靜態(tài)綁定的(參見條款38)。這意味著,因為pB被聲明為指向B的指針類型,通過pB調(diào)用非虛函數(shù)時將總是調(diào)用那些定義在類B中的函數(shù) - 即使pB指向的是從B派生的類的對象,如上例所示。相反,虛函數(shù)是動態(tài)綁定的(再次參見條款38),因而不會產(chǎn)生這類問題。如果mf是虛函數(shù),通過pB或pD調(diào)用mf時都將導(dǎo)致調(diào)用D:mf,因為pB和pD實際上指向的都是類型D的對象。所以,結(jié)論是,如

4、果寫類D時重新定義了從類B繼承而來的非虛函數(shù)mf,D的對象就可能表現(xiàn)出精神分裂癥般的異常行為。也就是說,D的對象在mf被調(diào)用時,行為有可能象B,也有可能象D,決定因素和對象本身沒有一點關(guān)系,而是取決于指向它的指針?biāo)暶鞯念愋?。引用也會和指針一樣表現(xiàn)出這樣的異常行為。實踐方面的論據(jù)就說這么多。我知道你現(xiàn)在想知道的是,不能重新定義繼承而來的非虛函數(shù)的理論依據(jù)是什么。我很高興解答。條款35解釋了公有繼承的含義是 是一個,條款36說明了為什么 在一個類中聲明一個非虛函數(shù)實際上為這個類建立了一種特殊性上的不變性。如果將這些分析套用到類B、類D和非虛成員函數(shù)B:mf,那么, 適用于B對象的一切也適用于D對

5、象,因為每個D的對象 是一個 B的對象。 B的子類必須同時繼承mf的接口和實現(xiàn),因為mf在B中是非虛函數(shù)。那么,如果D重新定義了mf,設(shè)計中就會產(chǎn)生矛盾。如果D真的需要實現(xiàn)和B不同的mf,而且每個B的對象 - 無論怎么特殊 - 也真的要使用B實現(xiàn)的mf,那么,每個D將不 是一個 B。這種情況下,D不能從B公有繼承。相反,如果D真的必須從B公有繼承,而且D真的需要和B不同的mf的實現(xiàn),那么,mf就沒有為B反映出特殊性上的不變性。這種情況下,mf應(yīng)該是虛函數(shù)。最后,如果每個D真的 是一個 B,并且如果mf真的為B建立了特殊性上的不變性,那么,D實際上就不需要重新定義mf,也就決不能這樣做。不管采用

6、上面的哪一種論據(jù)都可以得出這樣的結(jié)論:任何條件下都要禁止重新定義繼承而來的非虛函數(shù)。派生類和基類的關(guān)系:1: 派生類對象可以使用基類的方法,條件是方法不是私有的。2: 基類指針可以在不進(jìn)行顯示類型轉(zhuǎn)換的情況下指向派生類對象;基類引用可以在不進(jìn)行顯示類型轉(zhuǎn)換的情況下引用派生類對象;但基類指針或引用只能用于調(diào)用基類的方法;3: 不可以將基類對象和地址賦給派生類引用和指針;4: 將派生類引用或者指針轉(zhuǎn)換成為基類引用或指針被稱為向上強(qiáng)制轉(zhuǎn)換,不需要進(jìn)行顯示類型轉(zhuǎn)換。將基類指針或引用轉(zhuǎn)換為派生類指針或引用成為向下強(qiáng)制轉(zhuǎn)換。5: 如果基類函數(shù)中沒有使用虛函數(shù),使用類型轉(zhuǎn)換才有靜態(tài)編譯;如果基類中有虛函數(shù),

7、則采用動態(tài)聯(lián)編。編譯器處理虛函數(shù)的方法:給每個對象添加一個隱藏成員。隱藏成員中保存了一個指向函數(shù)的地址數(shù)組的指針。數(shù)組被成為虛函數(shù)表,虛函數(shù)表中存儲了為類對象進(jìn)行聲明的虛函數(shù)的地址。/*網(wǎng)上資料*/1. 用virtual關(guān)鍵字申明的函數(shù)叫做虛函數(shù),虛函數(shù)肯定是類的成員函數(shù)。2. 存在虛函數(shù)的類都有一個一維的虛函數(shù)表叫做虛表。類的對象有一個指向虛表開始的虛指針。虛表是和類對應(yīng)的,虛表指針是和對象對應(yīng)的。3. 多態(tài)性是一個接口多種實現(xiàn),是面向?qū)ο蟮暮诵摹7譃轭惖亩鄳B(tài)性和函數(shù)的多態(tài)性。4. 多態(tài)用虛函數(shù)來實現(xiàn),結(jié)合動態(tài)綁定。5. 純虛函數(shù)是虛函數(shù)再加上= 0。6. 抽象類是指包括至少一個純虛函數(shù)的類

8、。純虛函數(shù):virtual void breathe()=0;即抽象類!必須在子類實現(xiàn)這個函數(shù)!即先有名稱,沒內(nèi)容,在派生類實現(xiàn)內(nèi)容!虛標(biāo)指針的初始化:那么虛表指針在什么時候,或者說在什么地方初始化呢?答案是在構(gòu)造函數(shù)中進(jìn)行虛表的創(chuàng)建和虛表指針的初始化。還記得構(gòu)造函數(shù)的調(diào)用順序嗎,在構(gòu)造子類對象時,要先調(diào)用父類的構(gòu)造函數(shù),此時編譯器只“看到了”父類,并不知道后面是否后還有繼承者,它初始化父類對象的虛表指針,該虛表指針指向父類的虛表。當(dāng)執(zhí)行子類的構(gòu)造函數(shù)時,子類對象的虛表指針被初始化,指向自身的虛表。總結(jié)(基類有虛函數(shù)):1. 每一個類都有虛表。2. 虛表可以繼承,如果子類沒有重寫虛函數(shù),那么子

9、類虛表中仍然會有該函數(shù)的地址,只不過這個地址指向的是基類的虛函數(shù)實現(xiàn)。如果基類有3個虛函數(shù),那么基類的虛表中就有三項(虛函數(shù)地址),派生類也會有虛表,至少有三項,如果重寫了相應(yīng)的虛函數(shù),那么虛表中的地址就會改變,指向自身的虛函數(shù)實現(xiàn)。如果派生類有自己的虛函數(shù),那么虛表中就會添加該項。3. 派生類的虛表中虛函數(shù)地址的排列順序和基類的虛表中虛函數(shù)地址排列順序相同。 /虛基類 1, 一個類可以在一個類族中既被用作虛基類,也被用作非虛基類。 2, 在派生類的對象中,同名的虛基類只產(chǎn)生一個虛基類子對象,而某個非虛基類產(chǎn)生各自的子對象。 3, 虛基類子對象是由最派生類的構(gòu)造函數(shù)通過調(diào)用虛基類的構(gòu)造函數(shù)進(jìn)行

10、初始化的。 4, 最派生類是指在繼承結(jié)構(gòu)中建立對象時所指定的類。 5, 派生類的構(gòu)造函數(shù)的成員初始化列表中必須列出對虛基類構(gòu)造函數(shù)的調(diào)用;如果未列出,則表示使用該虛基類的缺省構(gòu)造函數(shù)。 6, 從虛基類直接或間接派生的派生類中的構(gòu)造函數(shù)的成員初始化列表中都要列出對虛基類構(gòu)造函數(shù)的調(diào)用。但只有用于建立對象的最派生類的構(gòu)造函數(shù)調(diào)用虛基類的構(gòu)造函數(shù),而該派生類的所有基類中列出的對虛基類的構(gòu)造函數(shù)的調(diào)用在執(zhí)行中被忽略,從而保證對虛基類子對象只初始化一次。 7, 在一個成員初始化列表中同時出現(xiàn)對虛基類和非虛基類構(gòu)造函數(shù)的調(diào)用時,虛基類的構(gòu)造函數(shù)先于非虛基類的構(gòu)造函數(shù)執(zhí)行。虛基類:如果一個派生類有多個直接基

11、類,而這些直接基類又有一個共同的基類,則在最終的派生類中會保留該間接共同基類數(shù)據(jù)成員的多份同名成員。現(xiàn)在,將類A聲明為虛基類,方法如下: class A /聲明基類A ; classB:virtual publicA /聲明類B是類A的公用派生類,A是B的虛基類 ; classC:virtual public A /聲明類C是類A的公用派生類,A是C的虛基類 ; 注意:虛基類并不是在聲明基類時聲明的,而是在聲明派生類時,指定繼承方式時聲明的。因為一個基類可以在生成一個派生類時作為虛基類,而在生成另一個派生類時不作為虛基類。 虛函數(shù) 1, 虛函數(shù)是非靜態(tài)的、非內(nèi)聯(lián)的成員函數(shù),而不能是友元函數(shù),但

12、虛函數(shù)可以在另一個類中被聲明為友元函數(shù)。 2, 虛函數(shù)聲明只能出現(xiàn)在類定義的函數(shù)原型聲明中,而不能在成員函數(shù)的函數(shù)體實現(xiàn)的時候聲明。 3, 一個虛函數(shù)無論被公有繼承多少次,它仍然保持其虛函數(shù)的特性。 4, 若類中一個成員函數(shù)被說明為虛函數(shù),則該成員函數(shù)在派生類中可能有不同的實現(xiàn)。當(dāng)使用該成員函數(shù)操作指針或引用所標(biāo)識的對象時,對該成員函數(shù)調(diào)用可采用動態(tài)聯(lián)編。 5, 定義了虛函數(shù)后,程序中聲明的指向基類的指針就可以指向其派生類。在執(zhí)行過程中,該函數(shù)可以不斷改變它所指向的對象,調(diào)用不同版本的成員函數(shù),而且這些動作都是在運行時動態(tài)實現(xiàn)的。虛函數(shù)充分體現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計的動態(tài)多態(tài)性。純虛函數(shù)版本的成員

13、函數(shù),而且這些動作都是在運行時動態(tài)實現(xiàn)的。虛函數(shù)充分體現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計的動態(tài)多態(tài)性。 純虛函數(shù) 1, 當(dāng)在基類中不能為虛函數(shù)給出一個有意義的實現(xiàn)時,可以將其聲明為純虛函數(shù),其實現(xiàn)留待派生類完成。 2, 純虛函數(shù)的作用是為派生類提供一個一致的接口。 3, 純虛函數(shù)不能實化化,但可以聲明指針。為什么構(gòu)造函數(shù)不能是虛函數(shù)2010-05-17 23:52:21|分類: c語言 |標(biāo)簽: |字號大中小訂閱 首先,讓我們假設(shè)他是虛的.當(dāng)我們在構(gòu)造函數(shù)中時并調(diào)用虛函數(shù).大家都知道,對于普通的成員函數(shù)虛函數(shù)的調(diào)用是在運行時決定的(即晚捆綁.因為在編譯時無法知道這個對象是屬于這個成員函數(shù)的那個類,還是屬于由

14、他派生出來的類).然而,在構(gòu)造函數(shù)中調(diào)用虛函數(shù)時,他所調(diào)用的僅僅是本地版本.也就是說,虛函數(shù)在構(gòu)造函數(shù)中并不工作! 第一,在概念上,構(gòu)造函數(shù)的工作是把對象變成存在物。在任何構(gòu)造函數(shù)中,對象可能只是部分被形成我們只能知道基類已被初始化了,但不知道哪個類是從這個基類繼承來的。然而,虛函數(shù)是“向前”和“向外”進(jìn)行調(diào)用。它能調(diào)用在派生類中的函數(shù)。如果我們在構(gòu)造函數(shù)中也這樣做,那么我們所調(diào)用的函數(shù)可能操作還沒有被初始化的成員,這將導(dǎo)致災(zāi)難的發(fā)生。 第二,。當(dāng)一個構(gòu)造函數(shù)被調(diào)用時,它做的首要的事情之一是初始化它的VPTR。因此,它只能知道它是“當(dāng)前”類的,而完全忽視這個對象后面是否還有繼承者。當(dāng)編譯器為這

15、個構(gòu)造函數(shù)產(chǎn)生代碼時,它是為這個類的構(gòu)造函數(shù)產(chǎn)生代碼-既不是為基類,也不是為它的派生類(因為類不知道誰繼承它)。所以它使用的VPTR必須是對于這個類的VTABLE。而且,只要它是最后的構(gòu)造函數(shù)調(diào)用,那么在這個對象的生命期內(nèi),VPTR將保持被初始化為指向這個VTABLE。但如果接著還有一個更晚派生的構(gòu)造函數(shù)被調(diào)用,這個構(gòu)造函數(shù)又將設(shè)置VPTR指向它的VTABLE,等.直到最后的構(gòu)造函數(shù)結(jié)束。VPTR的狀態(tài)是由被最后調(diào)用的構(gòu)造函數(shù)確定的。這就是為什么構(gòu)造函數(shù)調(diào)用是從基類到更加派生類順序的另一個理由。 但是,當(dāng)這一系列構(gòu)造函數(shù)調(diào)用正發(fā)生時,每個構(gòu)造函數(shù)都已經(jīng)設(shè)置VPTR指向它自己的VTABLE。如果

16、函數(shù)調(diào)用使用虛機(jī)制,它將只產(chǎn)生通過它自己的VTABLE的調(diào)用,而不是最后的VTABLE(所有構(gòu)造函數(shù)被調(diào)用后才會有最后的VTABLE)。另外,許多編譯器認(rèn)識到,如果在構(gòu)造函數(shù)中進(jìn)行虛函數(shù)調(diào)用,應(yīng)該使用早捆綁,因為它們知道晚捆綁將只對本地函數(shù)產(chǎn)生調(diào)用。無論哪種情況,在構(gòu)造函數(shù)中調(diào)用虛函數(shù)都沒有結(jié)果。 所以,構(gòu)造函數(shù)不能是虛的,然而,對于析構(gòu)函數(shù)來說他常常是,而且最好是虛的!這個此處暫時不議. 定義虛函數(shù)的限制: (1)非類的成員函數(shù)不能定義為虛函數(shù),類的成員函數(shù)中靜態(tài)成員函數(shù)和構(gòu)造函數(shù)也不能定義為虛函數(shù),但可以將析構(gòu)函數(shù)定義為虛函數(shù)。實際上,優(yōu)秀的程序員常常把基類的析構(gòu)函數(shù)定義為虛函數(shù)。因為,將

17、基類的析構(gòu)函數(shù)定義為虛函數(shù)后,當(dāng)利用delete刪除一個指向派生類定義的對象指針時,系統(tǒng)會調(diào)用相應(yīng)的類的析構(gòu)函數(shù)。而不將析構(gòu)函數(shù)定義為虛函數(shù)時,只調(diào)用基類的析構(gòu)函數(shù)。 (2)只需要在聲明函數(shù)的類體中使用關(guān)鍵字“virtual”將函數(shù)聲明為虛函數(shù),而定義函數(shù)時不需要使用關(guān)鍵字“virtual”。 (3)當(dāng)將基類中的某一成員函數(shù)聲明為虛函數(shù)后,派生類中的同名函數(shù)自動成為虛函數(shù)。 (4)如果聲明了某個成員函數(shù)為虛函數(shù),則在該類中不能出現(xiàn)和這個成員函數(shù)同名并且返回值、參數(shù)個數(shù)、類型都相同的非虛函數(shù)。在以該類為基類的派生類中,也不能出現(xiàn)這種同名函數(shù)。 虛函數(shù)聯(lián)系到多態(tài),多態(tài)聯(lián)系到繼承。所以本文中都是在繼

18、承層次上做文章。沒了繼承,什么都沒得談虛函數(shù)是如何做到的(如果你沒有看過Inside The C+ Object Model這本書,但又急切想知道,那你就應(yīng)該從這里開始) 虛函數(shù)是如何做到因?qū)ο蟮牟煌{(diào)用其相應(yīng)的函數(shù)的呢?現(xiàn)在我們就來剖析虛函數(shù)。我們先定義兩個類 class A /虛函數(shù)示例代碼 public: virtual void fun()cout1endl; virtual void fun2()cout2endl; ; class B:public A public: void fun()cout3endl; void fun2()cout4fun(); 毫無疑問,調(diào)用了A:fu

19、n(),但是A:fun()是如何被調(diào)用的呢?它像普通函數(shù)那樣直接跳轉(zhuǎn)到函數(shù)的代碼處嗎?No,其實是這樣的,首先是取出vptr的值,這個值就是vtbl的地址,再根據(jù)這個值來到vtbl這里,由于調(diào)用的函數(shù)A:fun()是第一個虛函數(shù),所以取出vtbl第一個slot里的值,這個值就是A:fun()的地址了,最后調(diào)用這個函數(shù)?,F(xiàn)在我們可以看出來了,只要vptr不同,指向的vtbl就不同,而不同的vtbl里裝著對應(yīng)類的虛函數(shù)地址,所以這樣虛函數(shù)就可以完成它的任務(wù)。 而對于class A和class B來說,他們的vptr指針存放在何處呢?其實這個指針就放在他們各自的實例對象里。由于class A和cla

20、ss B都沒有數(shù)據(jù)成員,所以他們的實例對象里就只有一個vptr指針。通過上面的分析,現(xiàn)在我們來實作一段代碼,來描述這個帶有虛函數(shù)的類的簡單模型。 #include using namespace std; /將上面“虛函數(shù)示例代碼”添加在這里 int main() void (*fun)(A*); A *p=new B; long lVptrAddr; memcpy(&lVptrAddr,p,4); memcpy(&fun,reinterpret_cast(lVptrAddr),4); fun(p); delete p; system(pause); 用VC或Dev-C+編譯運行一下,看看結(jié)果

21、是不是輸出3,如果不是,那么太陽明天肯定是從西邊出來。現(xiàn)在一步一步開始分析 void (*fun)(A*); 這段定義了一個函數(shù)指針名字叫做fun,而且有一個A*類型的參數(shù),這個函數(shù)指針待會兒用來保存從vtbl里取出的函數(shù)地址 A* p=new B; new B是向內(nèi)存(內(nèi)存分5個區(qū):全局名字空間,自由存儲區(qū),寄存器,代碼空間,棧)自由存儲區(qū)申請一個內(nèi)存單元的地址然后隱式地保存在一個指針中.然后把這個地址賦值給A類型的指針P. . long lVptrAddr; 這個long類型的變量待會兒用來保存vptr的值 memcpy(&lVptrAddr,p,4); 前面說了,他們的實例對象里只有vp

22、tr指針,所以我們就放心大膽地把p所指的4bytes內(nèi)存里的東西復(fù)制到lVptrAddr中,所以復(fù)制出來的4bytes內(nèi)容就是vptr的值,即vtbl的地址 現(xiàn)在有了vtbl的地址了,那么我們現(xiàn)在就取出vtbl第一個slot里的內(nèi)容 memcpy(&fun,reinterpret_cast(lVptrAddr),4); 取出vtbl第一個slot里的內(nèi)容,并存放在函數(shù)指針fun里。需要注意的是lVptrAddr里面是vtbl的地址,但lVptrAddr不是指針,所以我們要把它先轉(zhuǎn)變成指針類型 fun(p); 這里就調(diào)用了剛才取出的函數(shù)地址里的函數(shù),也就是調(diào)用了B:fun()這個函數(shù),也許你發(fā)現(xiàn)

23、了為什么會有參數(shù)p,其實類成員函數(shù)調(diào)用時,會有個this指針,這個p就是那個this指針,只是在一般的調(diào)用中編譯器自動幫你處理了而已,而在這里則需要自己處理。 delete p; 釋放由p指向的自由空間; system(pause); 屏幕暫停; 如果調(diào)用B:fun2()怎么辦?那就取出vtbl的第二個slot里的值就行了 memcpy(&fun,reinterpret_cast(lVptrAddr+4),4); 為什么是加4呢?因為一個指針的長度是4bytes,所以加4?;蛘適emcpy(&fun,reinterpret_cast(lVptrAddr)+1,4); 這更符合數(shù)組的用法,因為l

24、VptrAddr被轉(zhuǎn)成了long*型別,所以+1就是往后移sizeof(long)的長度 三, 以一段代碼開始#include using namespace std; class A /虛函數(shù)示例代碼2 public: virtual void fun() coutA:funendl; virtual void fun2()coutA:fun2endl; ; class B:public A public: void fun() coutB:funendl; void fun2() coutB:fun2*fun)(); fun = &A:fun2; (p-*fun)(); delete p;

25、 system(pause); 你能估算出輸出結(jié)果嗎?如果你估算出的結(jié)果是A:fun和A:fun2,呵呵,恭喜恭喜,你中圈套了。其實真正的結(jié)果是B:fun和B:fun2,如果你想不通就接著往下看。給個提示,&A:fun和&A:fun2是真正獲得了虛函數(shù)的地址嗎? 首先我們回到第二部分,通過段實作代碼,得到一個“通用”的獲得虛函數(shù)地址的方法 #include using namespace std; /將上面“虛函數(shù)示例代碼2”添加在這里 void CallVirtualFun(void* pThis,int index=0) void (*funptr)(void*); long lVptrA

26、ddr; memcpy(&lVptrAddr,pThis,4); memcpy(&funptr,reinterpret_cast(lVptrAddr)+index,4); funptr(pThis); /調(diào)用 int main() A* p=new B; CallVirtualFun(p); /調(diào)用虛函數(shù)p-fun() CallVirtualFun(p,1);/調(diào)用虛函數(shù)p-fun2() system(pause); CallVirtualFun方法現(xiàn)在我們擁有一個“通用”的CallVirtualFun方法。 這個通用方法和第三部分開始處的代碼有何聯(lián)系呢?聯(lián)系很大。由于A:fun()和A:fu

27、n2()是虛函數(shù),所以&A:fun和&A:fun2獲得的不是函數(shù)的地址,而是一段間接獲得虛函數(shù)地址的一段代碼的地址,我們形象地把這段代碼看作那段CallVirtualFun。編譯器在編譯時,會提供類似于CallVirtualFun這樣的代碼,當(dāng)你調(diào)用虛函數(shù)時,其實就是先調(diào)用的那段類似CallVirtualFun的代碼,通過這段代碼,獲得虛函數(shù)地址后,最后調(diào)用虛函數(shù),這樣就真正保證了多態(tài)性。同時大家都說虛函數(shù)的效率低,其原因就是,在調(diào)用虛函數(shù)之前,還調(diào)用了獲得虛函數(shù)地址的代碼。關(guān)于如何在派生類的虛函數(shù)中調(diào)用被覆蓋掉的同名基類的虛函數(shù),即Java中的super在C+中的使用方法 Posted on

28、 2009-03-25 23:00 魔kyo 閱讀(895) 評論(1) 編輯收藏 引用 很久沒寫B(tài)LOG了,這是在設(shè)計實現(xiàn)中遇到的一個實際問題,就是類似下面的Java代碼在C+中如何實現(xiàn)的問題1importjava.io.*;2importjava.util.*;34classB56publicvoidPrint()78System.out.println(B);9101112classDextendsB1314publicvoidPrint()1516super.Print();17System.out.println(D);18192021classMain2223publicstati

29、cvoidmain(Stringargs)2425Bobj=newD();26obj.Print();272829有時候我們需要將所有子類方法中都會執(zhí)行的代碼放到基類方法中,或者可能這些代碼是操作基類成員的本來就不應(yīng)該放在子類,在Java中可以通過super來調(diào)用被覆蓋掉的父類中的方法。我居然以為C+無法實現(xiàn)這一點,實在是太無知了。Google之后才知道原來可以這樣用1#include2usingnamespacestd;34classB56public:7virtualvoidPrint()89puts(B);1011;1213classD:publicB1415public:16virtu

30、alvoidPrint()1718B:Print();19puts(D);2021;2223intmain()2425B*p=newD();26p-Print();2728讓我認(rèn)為C+無法實現(xiàn)這點是有理由的,我們把virtual去掉看以下的代碼1#include2usingnamespacestd;34classB56public:7voidPrint()89puts(B);1011;1213classD:publicB1415public:16voidPrint()1718(B*)(this)-Print();19puts(D);2021;2223intmain()2425D*p=newD(

31、);26p-Print();2728這段代碼是可以正確實行的,因為沒有virtual,D類中的Print并沒有覆蓋B類中的Print,只是同名而已(這是很不好的做法,容易產(chǎn)生誤解),所以這時不存在運行時綁定,我只好D* p=new D(); 我認(rèn)為子類對象在內(nèi)存中是這樣的但是virtual的方法會被覆蓋掉,也就是說對于D類的對象,已經(jīng)沒有B類的Print方法了。所以如果加上virtual我們就無法正確執(zhí)行上面的代碼了。可是B:Print(); 又是如何實現(xiàn)的呢?Stockbroker GrapevineTime Limit: 1000MSMemory Limit: 10000KTotal Su

32、bmissions: 17482Accepted: 9439DescriptionStockbrokers are known to overreact to rumours. You have been contracted to develop a method of spreading disinformation amongst the stockbrokers to give your employer the tactical edge in the stock market. For maximum effect, you have to spread the rumours i

33、n the fastest possible way. Unfortunately for you, stockbrokers only trust information coming from their Trusted sources This means you have to take into account the structure of their contacts when starting a rumour. It takes a certain amount of time for a specific stockbroker to pass the rumour on

34、 to each of his colleagues. Your task will be to write a program that tells you which stockbroker to choose as your starting point for the rumour, as well as the time it will take for the rumour to spread throughout the stockbroker community. This duration is measured as the time needed for the last

35、 person to receive the information.InputYour program will input data for different sets of stockbrokers. Each set starts with a line with the number of stockbrokers. Following this is a line for each stockbroker which contains the number of people who they have contact with, who these people are, an

36、d the time taken for them to pass the message to each person. The format of each stockbroker line is as follows: The line starts with the number of contacts (n), followed by n pairs of integers, one pair for each contact. Each pair lists first a number referring to the contact (e.g. a 1 means person number one in the set), followed by the time in minutes taken to pass a message to that person.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論