C++在單繼承、多繼承.docx_第1頁
C++在單繼承、多繼承.docx_第2頁
C++在單繼承、多繼承.docx_第3頁
C++在單繼承、多繼承.docx_第4頁
C++在單繼承、多繼承.docx_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

一、本文目的與說明 1. 本文目的:理清在各種繼承時,構(gòu)造函數(shù)、復(fù)制構(gòu)造函數(shù)、賦值操作符、析構(gòu)函數(shù)的執(zhí)行順序和執(zhí)行內(nèi)容。 2. 說明:雖然復(fù)制構(gòu)造函數(shù)屬于構(gòu)造函數(shù)的一種,有共同的地方,但是也具有一定的特殊性,所以在總結(jié)它的性質(zhì)時將它單獨列出來了。 3. 單繼承、多繼承、虛繼承,既然都屬于繼承,那么雖然有一定的區(qū)別,但還是相同點比較多。如果放在一塊講,但為了將內(nèi)容制作成遞進的,就分開了,對相同點進行重復(fù),(大量的復(fù)制粘貼哈),但在不同點進行了標注。 注意:三塊內(nèi)容是逐步遞進的 如果你懂虛函數(shù),那么單繼承和多繼承那塊你就可以不看; 如果你懂多繼承,那單繼承你就不要看了,至于虛繼承就等你懂虛繼承再回來看吧; 如果你只懂單繼承,那你就只看單繼承就好。二、基本知識 1. 對于一個空類,例如;cppview plaincopyprint?1. classEmptyClass; 雖然你沒有聲明任何函數(shù),但是編譯器會自動為你提供上面這四個方法。cppview plaincopyprint?1. classEmptyClass2. public:3. EmptyClass();/默認構(gòu)造函數(shù)4. EmptyClass(constEmptyClass&rhs);/復(fù)制構(gòu)造函數(shù)5. EmptyClass();/析構(gòu)函數(shù)6. EmptyClass&operator=(constEmptyClass&rhs);/賦值運算符7. 對于這四個方法的任何一個,你的類如果沒有聲明,那么編譯器就會自動為你對應(yīng)的提供一個默認的。(在C+ primer中,這個編譯器自動提供的版本叫做“合成的*”,例如合成的復(fù)制構(gòu)造函數(shù))當(dāng)然如果你顯式聲明了,編譯器就不會再提供相應(yīng)的方法。 2.合成的默認構(gòu)造函數(shù)執(zhí)行內(nèi)容:如果有父類,就先調(diào)用父類的默認構(gòu)造函數(shù)。 2.合成的復(fù)制構(gòu)造函數(shù)執(zhí)行內(nèi)容:使用參數(shù)中的對象,構(gòu)造出一個新的對象。 3.合成的賦值操作符執(zhí)行內(nèi)容:使用參數(shù)中的對象,使用參數(shù)對象的非static成員 依次對 目標對象的成員賦值。注意:在賦值操作符執(zhí)行之前,目標對象已經(jīng)存在。 4. 在繼承體系中,要將基類(或稱為父類)的析構(gòu)函數(shù),聲明為virtual方法(即虛函數(shù))。 5. 子類中包含父類的成員。即子類有兩個部分組成,父類部分和子類自己定義的部分。 6. 如果在子類中顯式調(diào)用父類的構(gòu)造函數(shù),只能在構(gòu)造函數(shù)的初始化列表中調(diào)用,并且只能調(diào)用其直接父類的。 7. 在多重繼承時,按照基類繼承列表中聲明的順序初始化父類。 8. 在虛繼承中,虛基類的初始化早于非虛基類,并且子類來初始化虛基類(注意:虛基類不一定是子類的直接父類)。三、單繼承核心:在構(gòu)造子類之前一定要執(zhí)行父類的一個構(gòu)造函數(shù)。1.構(gòu)造函數(shù)(不包括復(fù)制構(gòu)造函數(shù))。 順序:直接父類;自己 注意:若直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有顯式定義構(gòu)造函數(shù),則“合成的默認構(gòu)造函數(shù)”會自動調(diào)用直接父類的“默認構(gòu)造函數(shù)”,然后調(diào)用編譯器為自己自動生成的“合成的默認構(gòu)造函數(shù)”。 2.2 如果顯式定義了自己的構(gòu)造函數(shù) 2.2.1 如果沒有顯式調(diào)用直接父類的任意一個構(gòu)造函數(shù),那么和“合成的默認構(gòu)造函數(shù)”一樣,會先自動調(diào)用直接父類的 默認構(gòu)造函數(shù),然后調(diào)用自己的構(gòu)造函數(shù)。 2.2.2 如果顯式調(diào)用了直接父類的任意一個構(gòu)造函數(shù),那么會先調(diào)用直接父類相應(yīng)的構(gòu)造函數(shù),然后調(diào)用自己的構(gòu)造函數(shù)。2. 復(fù)制構(gòu)造函數(shù) 順序:直接父類;自己 注意:和構(gòu)造函數(shù)一樣,若直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有顯式定義復(fù)制構(gòu)造函數(shù),則“合成的復(fù)制構(gòu)造函數(shù)”會自動調(diào)用直接父類的“復(fù)制構(gòu)造函數(shù)”,然后調(diào)用編譯器為自己自動生成的“合成的復(fù)制構(gòu)造函數(shù)”(注意:不是默認構(gòu)造函數(shù)) 2.2 如果顯式定義了自己的復(fù)制構(gòu)造函數(shù) (和構(gòu)造函數(shù)類似) 2.2.1 如果沒有顯式調(diào)用父類的任意一個構(gòu)造函數(shù),那么會先調(diào)用直接父類的 默認構(gòu)造函數(shù)(注意:不是 復(fù)制構(gòu)造函數(shù))。 2.2.2 如果顯式調(diào)用了直接父類的任意一個構(gòu)造函數(shù),那么會先調(diào)用直接父類相應(yīng)的構(gòu)造函數(shù)。3.賦值操作符重載 3.1 如果沒有顯式定義,會自動調(diào)用直接父類的賦值操作符。(注意:不是 默認構(gòu)造函數(shù)) 3.2 如果顯式定義了,就只執(zhí)行自己定義的版本,不再自動調(diào)用直接父類的賦值操作符,只執(zhí)行自己的賦值操作符。 注意:如有需要對父類子部分進行賦值,應(yīng)該在自己編寫的代碼中,顯式調(diào)用父類的賦值操作符。4. 析構(gòu)函數(shù) 與構(gòu)造函數(shù) 順序相反。四、多繼承和單繼承的差別就是:需要考慮到多個直接父類。其它的都相同1.構(gòu)造函數(shù)(不包括復(fù)制構(gòu)造函數(shù))。 順序:所有直接父類;(按照基類繼承列表中聲明的順序)自己 注意:若直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有 顯式定義構(gòu)造函數(shù),則“合成的默認構(gòu)造函數(shù)”會自動依次調(diào)用所有直接父類的“默認構(gòu)造函數(shù)”,然后調(diào)用編譯器為自己自動生成的“合成的默認構(gòu)造函數(shù)”。 2.2 如果顯式定義了自己的構(gòu)造函數(shù) 2.2.1 如果沒有顯式調(diào)用父類的任意一個構(gòu)造函數(shù),那么和“合成的默認構(gòu)造函數(shù)”一樣,會自動依次調(diào)用所有直接父類的 默認構(gòu)造函數(shù),然后調(diào)用自己的構(gòu)造函數(shù)。 2.2.2 如果顯式調(diào)用了父類的任意一個構(gòu)造函數(shù),那么按照基類列表的順序,對于每一個父類依次判斷:若顯式調(diào)用了構(gòu)造函數(shù),那么會調(diào)用該父類相應(yīng)的構(gòu)造函數(shù);如果沒有顯式調(diào)用,就調(diào)用默認構(gòu)造函數(shù)。最后調(diào)用自己的構(gòu)造函數(shù)。2. 復(fù)制構(gòu)造函數(shù) 順序:所有直接父類;(按照基類繼承列表中聲明的順序)自己 注意:和構(gòu)造函數(shù)一樣,若直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有顯式定義復(fù)制構(gòu)造函數(shù),則“合成的復(fù)制構(gòu)造函數(shù)”會自動依次調(diào)用所有直接父類的“復(fù)制構(gòu)造函數(shù)”,然后調(diào)用編譯器為自己自動生成的“合成的復(fù)制構(gòu)造函數(shù)”(注意:不是默認構(gòu)造函數(shù)) 2.2 如果顯式定義了自己的復(fù)制構(gòu)造函數(shù) (和構(gòu)造函數(shù)類似) 2.2.1 如果沒有顯式調(diào)用父類的任意一個構(gòu)造函數(shù),那么會先自動依次調(diào)用直接父類的 默認構(gòu)造函數(shù)(注意:不是 復(fù)制構(gòu)造函數(shù))。 2.2.2 如果顯式調(diào)用了直接父類的任意一個構(gòu)造函數(shù),那么按照基類列表的順序,對于每一個父類依次判斷:若顯式調(diào)用了構(gòu)造函數(shù),那么會調(diào)用該父類相應(yīng)的構(gòu)造函數(shù);如果沒有顯式調(diào)用,就調(diào)用默認構(gòu)造函數(shù)。最后調(diào)用自己的復(fù)制構(gòu)造函數(shù)。3.賦值操作符重載 3.1 如果沒有顯式定義,會自動依次調(diào)用直接父類的賦值操作符。(注意:不是 默認構(gòu)造函數(shù)) 3.2 如果顯式定義了,就只執(zhí)行自己定義的版本,不再自動調(diào)用直接父類的賦值操作符,只執(zhí)行自己的賦值操作符。 注意:如有需要對父類子部分進行賦值,應(yīng)該在自己編寫的代碼中,顯式調(diào)用所有直接父類的賦值操作符。4. 析構(gòu)函數(shù) 與 構(gòu)造函數(shù) 順序相反。五、虛繼承和多繼承的差別就是:要考慮到虛基類,其它的都相同。(虛基類的初始化要早于非虛基類,并且只能由子類對其進行初始化)1.構(gòu)造函數(shù)(不包括復(fù)制構(gòu)造函數(shù))。 順序:所有虛基類(按照基類繼承列表中聲明的順序進行查找);所有直接父類;(按照基類繼承列表中聲明的順序)自己 注意:若虛基類或者直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造,“虛基類的父類”也會在“虛基類”之前構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有 顯式定義構(gòu)造函數(shù),則“合成的默認構(gòu)造函數(shù)”會先依次調(diào)用所有虛基類的默認構(gòu)造函數(shù),然后再自動依次調(diào)用所有直接父類的“默認構(gòu)造函數(shù)”,最后調(diào)用編譯器為自己自動生成的“合成的默認構(gòu)造函數(shù)”。 2.2 如果顯式定義了自己的構(gòu)造函數(shù) 2.2.1 如果沒有顯式調(diào)用父類的任意一個構(gòu)造函數(shù),那么和“合成的默認構(gòu)造函數(shù)”一樣,會先依次調(diào)用所有虛基類的默認構(gòu)造函數(shù),然后再自動依次調(diào)用所有直接父類的 默認構(gòu)造函數(shù),最后調(diào)用自己的構(gòu)造函數(shù)。 2.2.2 如果顯式調(diào)用了父類的任意一個構(gòu)造函數(shù),那么按照基類列表的順序,先初始化所有虛基類,再初始化所有直接父類。對于每一個父類依次判斷:若顯式調(diào)用了構(gòu)造函數(shù),那么會調(diào)用該父類相應(yīng)的構(gòu)造函數(shù);如果沒有顯式調(diào)用,就調(diào)用默認構(gòu)造函數(shù)。最后調(diào)用自己的構(gòu)造函數(shù)。2. 復(fù)制構(gòu)造函數(shù) 順序:所有虛基類(按照基類繼承列表中聲明的順序進行查找);所有直接父類;(按照基類繼承列表中聲明的順序)自己 注意:和構(gòu)造函數(shù)一樣,若虛基類或者直接父類還有父類,那么“直接父類的父類”會在“直接父類” 之前 構(gòu)造,“虛基類的父類”也會在“虛基類”之前構(gòu)造。 可以理解為這是一個遞歸的過程,知道出現(xiàn)一個沒有父類的類才停止。 2.1 如果沒有顯式定義復(fù)制構(gòu)造函數(shù),則“合成的復(fù)制構(gòu)造函數(shù)”會自動依次調(diào)用所有直接父類的“復(fù)制構(gòu)造函數(shù)”,然后調(diào)用編譯器為自己自動生成的“合成的復(fù)制構(gòu)造函數(shù)”(注意:不是默認構(gòu)造函數(shù)) 2.2 如果顯式定義了自己的復(fù)制構(gòu)造函數(shù) (和構(gòu)造函數(shù)類似) 2.2.1 如果沒有顯式調(diào)用父類的任意一個構(gòu)造函數(shù),那么會先依次調(diào)用所有虛基類的默認構(gòu)造函數(shù),然后再依次調(diào)用所有直接父類的 默認構(gòu)造函數(shù)(注意:不是 復(fù)制構(gòu)造函數(shù))。 2.2.2 如果顯式調(diào)用了直接父類的任意一個構(gòu)造函數(shù),那么按照基類列表的順序,先初始化所有虛基類,再初始化所有直接父類。對于每一個父類依次判斷:若顯式調(diào)用了構(gòu)造函數(shù),那么會調(diào)用該父類相應(yīng)的構(gòu)造函數(shù);如果沒有顯式調(diào)用,就調(diào)用默認構(gòu)造函數(shù)。3.賦值操作符重載 3.1 如果沒有顯式定義,會自動依次調(diào)用所有虛基類和所有直接父類的賦值操作符。(注意:不是 默認構(gòu)造函數(shù)) 3.2 如果顯式定義了,就只執(zhí)行自己定義的版本,不再自動調(diào)用直接父類的賦值操作符,只執(zhí)行自己的賦值操作符。 注意:如有需要對父類子部分進行賦值,應(yīng)該在自己編寫的代碼中,顯式調(diào)用所有虛基類和所有直接父類的賦值操作符。4. 析構(gòu)函數(shù) 與 構(gòu)造函數(shù) 順序相反。六、總結(jié):1.整體順序:虛基類 - 直接父類 -自己2. 在任何顯式定義的構(gòu)造函數(shù)中,如果沒有顯式調(diào)用父類的構(gòu)造函數(shù),那么就會調(diào)用父類的默認構(gòu)造函數(shù)。3.合成的復(fù)制構(gòu)造函數(shù)、合成的賦值操作符,(當(dāng)沒有顯式定義時,編譯器自動提供),會自動調(diào)用的是虛基類和直接父類的復(fù)制構(gòu)造函數(shù)和賦值操作符,而不是默認構(gòu)造函數(shù);4. 自己顯式定義的復(fù)制構(gòu)造函數(shù),除非在初始化列表中顯示調(diào)用,否則只會調(diào)用虛基類和父類的默認構(gòu)造函數(shù)。5. 自己顯式定義的賦值操作符,除非顯式調(diào)用,否則只執(zhí)行自己的代碼。6. 析構(gòu)函數(shù)的執(zhí)行順序與 構(gòu)造函數(shù) 相反。七、例子程序話說只有自己寫一個程序,然后研究運行結(jié)果,才會掌握的更好。所以下面就是個例子程序了??梢愿鶕?jù)需要,注釋掉某個類的相應(yīng)函數(shù),觀察結(jié)果。1. 該例子的繼承層次圖為:(M和N是虛基類)2. 代碼如下cppview plaincopyprint?1. #include2. usingnamespacestd;3. 4. classA5. public:6. A()7. coutintA:A()endl;8. 9. A(A&a)10. coutintA:A(A&a)endl;11. 12. A&operator=(A&a)13. coutintA:operator=(A&a)endl;14. returna;15. 16. virtualA()17. coutintA:A()endl;18. 19. ;20. 21. classM:publicA22. public:23. M()24. coutintM:M()endl;25. 26. M(M&a)27. coutintM:M(M&a)endl;28. 29. M&operator=(M&m)30. coutintM:operator=(M&a)endl;31. returnm;32. 33. virtualM()34. coutintM:M()endl;35. 36. ;37. 38. classB:virtualpublicM39. public:40. B()41. coutintB:B()endl;42. 43. B(B&a)44. coutintB:B(B&a)endl;45. 46. B&operator=(B&b)47. coutintB:operator=(B&a)endl;48. returnb;49. 50. virtualB()51. coutintB:B()endl;52. 53. 54. ;55. 56. classN:publicA57. public:58. N()59. coutintN:N()endl;60. 61. N(N&a)62. coutintN:N(N&a)endl;63. 64. N&operator=(N&n)65. coutintN:operator=(N&a)endl;66. returnn;67. 68. virtualN()69. coutintN:N()endl;70. 71. ;72. classC:virtualpublicN73. public:74. C()75. coutintC:C()endl;76. 77. C(C&a)78. coutintC:C(C&a)endl;79. 80. C&operator=(C&c)81. coutintC:operator=(C&a)endl;82. returnc;83. 84. virtualC()85. coutintC:C()endl;86. 87. ;88. classE:virtualpublicM89. public:90. E()91. coutintE:E()endl;92. 93. E(E&a)94. coutintE:E(E&a)endl;95. 96. E&operator=(E&e)97. coutintE:operator=(E&a)endl;98. returne;99. 100. virtualE()101. coutintE:E()endl;102. 103. ;104. classD:publicB,publicC,publicE105. public:106. D()107. coutintD:D()endl;108. 109. D(D&a)110. coutintD:D(D&a)endl;111. 112. D&operator=(D&d)113. coutintD:operator=(D&a)endl;114. returnd;115. 116. virtualD()117. coutintD:D()endl;118. 119. ;120. 121. 122. intmain(intargc,char*argv)123. cout-構(gòu)造函數(shù)-endl;124. Dd;125. cout-復(fù)制構(gòu)造函數(shù)-endl;126. Dd1(d);127. cout-賦值操作符-endl;128. d=d1;129. cout-析構(gòu)函數(shù)-endl;130. 131. 132. return0;133. 3. 運行結(jié)果與分析 分析:M和N是虛基類,但是A不是虛基類。B和E共享一個M,但是M和N都會含有類A的部分,因為A不是虛基類,所以M和N不共享A。下面的注釋部分為添加的分析。

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論