第4章 類的繼承和派生.ppt_第1頁
第4章 類的繼承和派生.ppt_第2頁
第4章 類的繼承和派生.ppt_第3頁
第4章 類的繼承和派生.ppt_第4頁
第4章 類的繼承和派生.ppt_第5頁
已閱讀5頁,還剩52頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第四章繼承和派生 4 1繼承和派生的概念 面向對象程序設計有4個主要特點 抽象 封裝 繼承和多態(tài)性 在本章中主要介紹有關繼承的知識 在下一章中將介紹多態(tài)性 C 語言提供了類的繼承機制 解決了軟件重用問題 4 1 1繼承與派生的概念 一個類中包含了若干數據成員和成員函數 在不同的類中 數據成員和成員函數是不相同的 但有時兩個類的內容基本相同或有一部分相同 類的繼承 一個新類從已存在的類那里獲得該類已有的特性叫作類的繼承 已存在的類叫作父類 也叫作基類 產生的新類叫作子類或派生類 類的派生 從一個已有的類那里產生一個新類的過程叫類的派生 已存在的類叫作父類 也叫作基類 產生的新類叫作派生類或子類 類的繼承和派生是同一概念 前者是從子類的角度來說 后者是從父類的角度來說的 我們通常說子類繼承了父類 父類派生了子類 描述各級學生的類的繼承關系如下圖 基類與派生類的關系 派生類是基類的具體化 基類則是派生類的抽象一個派生類的對象也是一個基類的對象 應該具有基類的一切屬性和方法 派生類除了具有基類的一切屬性和方法外 還可以有自己所特有的屬性和方法 4 1 2派生類和基類的關系 4 1 3單繼承與多繼承 單繼承 一個派生類只從一個基類繼承 多重繼承 一個派生類從兩個或多個基類繼承 4 2派生類的聲明方式 聲明派生類的一般形式為class派生類名 繼承方式 基類名 派生類新增加的成員 繼承方式包括 public 公有的 private 私有的 和protected 受保護的 此項是可選的 如果不寫此項 則默認為private 私有的 如下程序演示了類Rectangle 四邊形 由類Point繼承而來 voidSetPoint intx inty this x x this y y voidMovePoint intdx intdy x dx y dy voidShowPoint cout x y Point h include includeusingnamespacestd classPoint private intx y public intGetX returnx intGetY returny voidSetRect intx inty intw inth SetPoint x y width w height h voidShowRect cout 左上角坐標為 ShowPoint cout endl cout 寬為 width endl cout 長為 height endl Rectangle h include include Point h usingnamespacestd classRectangle publicPoint private intwidth intheight public intGetWidth returnwidth intGetHight returnheight main cpp include Rectangle h voidmain Rectangler r SetRect 0 0 10 20 r ShowRect r MovePoint 10 10 r ShowRect 4 3派生類的構成 派生類中的成員包括從基類繼承過來的成員和自己增加的成員兩大部分 在基類中包括數據成員和成員函數 或稱數據與方法 兩部分 派生類分為兩大部分 一部分是從基類繼承來的成員 另一部分是在聲明派生類時增加的部分 每一部分均分別包括數據成員和成員函數 如果在派生類中定義了和基類中同名函數 函數參數個數和類型可以相同也可以不相同 則派生類中的函數會隱藏基類的同名函數 在派生類中不能直接訪問基類中的同名函數 注意與重載的區(qū)別 在同一個類中的同名不同參函數為重載函數 如程序PointRect1所示 4 4繼承方式 派生類的繼承方式有三種 public private protected 不同的繼承方式決定了基類成員在派生類中的訪問屬性 4 4 1類的保護成員 前面介紹過類的成員 數據成員和成員函數 的訪問屬性有私有的 private 的和公有的 public的 另外還提到類的訪問屬性也可以有保護的 protected的 類中的protected成員與private成員一樣 只能在本類的成員函數中訪問 不能在類外通過對象來訪問 但通過上面的表中可以看出當類派生時 基類的private成員在派生類中是不可訪問的 而基類的protected成員在派生類中隨繼承方式的不同而不同 classDrived publicBase protected intj public voidFun i 20 includeusingnamespacestd classBase protected inti public voidF voidmain Drivedd 4 5派生類的構造函數和析構函數 構造函數的主要作用是對數據成員初始化 在設計派生類的構造函數時 不僅要考慮派生類所增加的數據成員的初始化 還應當考慮基類的數據成員初始化 也就是說 希望在執(zhí)行派生類的構造函數時 使派生類的數據成員和基類的數據成員同時都被初始化 解決這個問題的思路是 在執(zhí)行派生類的構造函數時 調用基類的構造函數 注意 派生類繼承基類的除構造函數和析構函數以外的所有函數 4 4 1簡單的派生類的構造函數 簡單的派生類 只有一個基類 而且只有一級派生 只有直接派生類 沒有間接派生類 在派生類的數據成員中不包含基類的對象 即子對象 簡單派生類中我們一般采用在派生類的構造函數初始化列表中調用基類的構造函數來對繼承基類的數據成員進行初始化 其一般形式為 派生類構造函數名 總參數表列 基類構造函數名 參數表列 派生類中新增數據成員初始化語句 簡單派生類的構造函數的形式 include includeusingnamespacestd classStudent public Student intn stringnam chars num n name nam sex s Student protected intnum stringname charsex classStudent1 publicStudent public Student1 intn stringnam chars inta stringad Student n nam s age a addr ad voidshow cout num num endl cout name name endl cout sex sex endl cout age age endl cout address addr endl endl Student1 private intage stringaddr 在main函數中 建立對象stud1時指定了5個實參 它們按順序傳遞給派生類構造函數Student1的形參 然后 派生類構造函數將前面3個傳遞給基類構造函數的形參 簡單派生類的構造函數的幾點說明 a 定義派生類的對象時系統(tǒng)自動調用派生類構造函數之前會先調用其基類的構造函數 基類的構造函數是在派生類的構造函數的初始化列表中給出 如果在初始化列表中沒顯式給出調用語句則調用基類的默認構造函數 例如前例中派生類的構造函數為 Student1 intn stringnam chars inta stringad Student n nam s 如果在main函數中定義一個Student1類的對象時 系統(tǒng)會先調用基類的構造函數 然后執(zhí)行Student1的構造函數體內的代碼完成對派生類成員的構造 如果Student1類的構造函數改為Student1 intn stringnam char 則會先調用基類的默認構造函數 當派生類構造函數在類外定義時 則只在類外的函數定義處加上調用基類的初始化列表 在類內申明的地方不加 由前面例題中的構造函數Student1 intn stringnam chars inta stringad Student n nam s 可以看出派生類的構造函數的初始化列表中是在調用基類的構造函數而不是在申明或定義基類的構造函數 所以Student1中的五個參數是形參 帶參數類型 而其初始化列表中的Student的三個參數是實參 不帶有類型 這些實參取自Student1 所以Studen中的三個參數也可以為常數 例如可將Student1的構造函數改為 Student1 stringnam chars inta stringad Student 10010 nam s 在派生類對象釋放時先執(zhí)行派生類的析構函數 然后執(zhí)行基類的析構函數 例題 定義一個點類Point 由Point派生出一個圓類Circle Point h文件 ifndefPOINT H definePOINT HclassPoint protected floatx floaty public Point x 0 y 0 Point floatx floaty voidShow endif Point cpp文件 include include Point h usingnamespacestd Point Point floatx floaty this x x this y y voidPoint Show cout x y endl Circle h文件 ifndefCIRCLE H defineCIRCLE H include include Point h usingnamespacestd classCircle publicPoint protected floatr public Circle floatx floaty floatr voidShow floatGetArea floatGetLength endif Circle cpp文件 include include CirCle h usingnamespacestd Circle Circle floatx floaty floatr Point x y this r r voidCircle Show cout 圓心為 Point x y Show cout 半徑為 r endl floatCircle GetArea return3 14159 r r floatCircle GetLength return3 14159 2 r 4 5 2有子對象的派生類的構造函數 類的數據成員中還可以包含類對象 例如前面的Student1類繼承自Student類 我們可以在Student1類中加入一個Student類的對象來表示該同學所在班的班長 如下程序所示 include includeusingnamespacestd classStudent public Student intn stringnam num n name nam voiddisplay cout num num endl name name endl protected intnum stringname classStudent1 publicStudent public Student1 intn stringnam intn1 stringnam1 inta stringad Student n nam monitor n1 nam1 age a addr ad voidshow cout 學生信息為 endl display cout age age endl cout address addr endl cout 班長為 endl monitor display private Studentmonitor intage stringaddr intmain Student1stud1 10010 Wang li 10001 Li sun 19 115BeijingRoad Shanghai stud1 show return0 派生類構造函數的任務應該包括3個部分 1 對基類數據成員初始化 2 對子對象數據成員初始化 3 對派生類數據成員初始化 其中前兩個必須放在派生類的構造函數的初始化列表中進行 第 3 個可以在函數體中也可以在初始化列表中進行 定義派生類構造函數的一般形式為派生類構造函數名 總參數表列 基類構造函數名 參數表列 子對象名 參數表列 派生類中新增數成員據成員初始化語句 執(zhí)行派生類構造函數的順序是 調用基類構造函數 對基類數據成員初始化 調用子對象構造函數 對子對象數據成員初始化 再執(zhí)行派生類構造函數本身 對派生類數據成員初始化 以上次序是固定的 不會因為基類構造函數調用寫在前面還是子對象名寫在前面而改變 例題 定義一個點類Point 由Point派生出一個圓類Circle Point h文件 ifndefPOINT H definePOINT HclassPoint protected floatx floaty public Point x 0 y 0 Point floatx floaty voidShow endif Point cpp文件 include include Point h usingnamespacestd Point Point floatx floaty this x x this y y voidPoint Show cout x y endl 4 5 3多層派生時的構造函數 Circle h文件 ifndefCIRCLE H defineCIRCLE H include include Point h usingnamespacestd classCircle publicPoint protected floatr public Circle floatx floaty floatr voidShow floatGetArea floatGetLength endif Circle cpp文件 include include CirCle h usingnamespacestd Circle Circle floatx floaty floatr Point x y this r r voidCircle Show cout 圓心為 Point x y Show cout 半徑為 r endl floatCircle GetArea return3 14159 r r floatCircle GetLength return3 14159 2 r column h ifndefCOLUMN H defineCOLUNM H include Circle h classColumn publicCircle private floath public Column floatx floaty floatr floath Circle x y r this h h voidShow floatGetArea floatGetVolume endif Column cpp include Column h includeusingnamespacestd voidColumn Show Circle Show cout 高為 h endl floatColumn GetArea return2 Circle GetArea GetLength h floatColumn GetVolume returnCircle GetArea h 在多層派生的情況下 派生類的構造函數初始化列表中只須寫出其上一層派生類的構造函數 不要再寫上其間接子類的構造函數 4 5 4派生類的析構函數 在派生時 派生類是不能繼承基類的析構函數的 也需要通過派生類的析構函數去調用基類的析構函數 在派生類中可以根據需要定義自己的析構函數 用來對派生類中所增加的成員進行清理工作 基類的清理工作仍然由基類的析構函數負責 在執(zhí)行派生類的析構函數時 系統(tǒng)會自動調用基類的析構函數和子對象的析構函數 對基類和子對象進行清理 調用的順序與構造函數正好相反 先執(zhí)行派生類自己的析構函數 對派生類新增加的成員進行清理 然后調用子對象的析構函數 對子對象進行清理 最后調用基類的析構函數 對基類進行清理 4 6多重繼承 前面討論的是單繼承 即一個類是從一個基類派生而來的 實際上 常常有這樣的情況 一個派生類有兩個或多個基類 派生類從兩個或多個基類中繼承所需的屬性 C 為了適應這種情況 允許一個派生類同時繼承多個基類 這種行為稱為多重繼承 multipleinheritance 4 6 1聲明多重繼承的方式 聲多重繼承子類的方法和單繼承相似 只是在標明子類的位置將繼承的父類都寫上 且以豆號隔開 例如類 多重繼承了類A B C則申明類 的方法如下 classD publicA protectedB privateC 類 新增加的成員 多重繼承的子類具有多個父類 子類中具有所有父類的所有成員 且對多個父類可以有不同的繼承方式 不同的繼承方式決定了繼承而來的父類的成員在子類中的訪問屬性的不同 4 6 2多重繼承的派生類的構造函數 多重繼承派生類的構造函數形式與單繼承時的構造函數形式基本相同 只是在初始列表中包含多個基類構造函數 形式如下 派生類構造函數名 總參數表列 基類1構造函數 參數表列 基類2構造函數 參數表列 基類3構造函數 參數表列 派生類中新增數據成員成員初始化語句 派生類構造函數的執(zhí)行順序同樣為 先調用基類的構造函數 再執(zhí)行派生類構造函數的函數體 調用基類構造函數的順序是按照聲明派生類時基類出現(xiàn)的順序 與構造函數初始化列表中基類的排列順序無關 include includeusingnamespacestd classTeacher public Teacher stringnam inta stringt name nam age a title t voiddisplay cout name name endl cout age age endl cout title title endl protected stringname intage stringtitle classStudent public Student stringnam chars floatsco name1 nam sex s score sco voiddisplay1 cout name name1 endl cout sex sex endl cout score score endl protected stringname1 charsex floatscore classGraduate publicTeacher publicStudent public Graduate stringnam inta chars stringt floatsco floatw Teacher nam a t Student nam s sco wage w voidshow cout name name endl cout age age endl cout sex sex endl cout score score endl cout title title endl cout wages wage endl private floatwage intmain Graduategrad1 Wang li 24 m assistant 89 5 1234 5 grad1 show return0 在兩個基類中分別用name和name1來代表姓名 其實這是同一個人的名字 從Graduate類的構造函數中可以看到總參數表中的參數nam分別傳遞給兩個基類的構造函數 作為基類構造函數的實參 解決這個問題有一個好方法 在兩個基類中可以都使用同一個數據成員名name 而在show函數中引用數據成員時指明其作用域 如cout name Teacher name endl 這就是惟一的 不致引起二義性 能通過編譯 正常運行 通過這個程序還可以發(fā)現(xiàn)一個問題 在多重繼承時 從不同的基類中會繼承一些重復的數據 如果有多個基類 問題會更突出 在設計派生類時要細致考慮其數據成員 盡量減少數據冗余 4 6 3多重繼承引起的二義性問題 多重繼承可以反映現(xiàn)實生活中的情況 能夠有效地處理一些較復雜的問題 使編寫程序具有靈活性 但是多重繼承也引起了一些值得注意的問題 它增加了程序的復雜度 使程序的編寫和維護變得相對困難 容易出錯 其中最常見的問題就是繼承的成員同名而產生的二義性 ambiguous 問題 a 多個基類中有同名成員 include includeusingnamespacestd classA protected inta public A inta this a a voiddisplay couta a voiddisplay cout B a a endl classC publicA publicB private intb public C intAa intBa intb A Aa B Ba this b b voidshow A display B display cout C b b endl voidmain Cc 1 2 3 c display 二義性 c show c B display 所以類 中數據成員全名應該為下圖所示 b 多個基類和派生類中都有同名成員 classC publicA publicB private inta public C intAa intBa intCa A Aa B Ba a Ca voiddisplay A display B display cout C a a endl 將前面的 類改為如下的形式 這時類 的成員構成如左圖所示 在類中有三個a 三個display 函數 思考 如下的main函數能否執(zhí)行 voidmain Cc 1 2 3 c display c A display c B display 這時c dispaly是可以執(zhí)行的 原因是類 中提供的display函數隱藏了基類 和基類 中的display函數 所以直接訪問display函數是在訪問類 中新增加的成員函數display C 如果類A和類B是從同一個基類派生的 前面提到派生類的對象也是基類的對象 因為派生類中繼承了基類中的所有成員 除構造函數和析構函數 準確的說應該是 公有派生類的對象是基類的對象 因為只有公有派生類中成員的訪問屬性與基類完全相同 基類能實現(xiàn)的功能在公有派生類中一定能夠實現(xiàn) 4 7基類與派生類的轉換 基本數據類型在一定條件下可以進行類型轉化 那么基類對象與派生類對象之間是不是也可以進行轉化 由于公有派生類對象也是基類的對象 所以派生類對象可以自動轉化為基類對象 表現(xiàn)在以下幾方面 include includeusingnamespacestd classPerson public Person stringnam chars inta name nam sex s age a Person diplay cout 姓名 name endl cout 性別 sex endl cout 年齡 age endl protected stringname charsex intage classTeacher publicPerson public Teacher stringnam chars inta stringt Person nam s a title t Teacher diplay Person diplay cout 職稱 title protected stringtitle voidmain Teachert zhangSan m 25 assistant Personp t p diplay Personp zhangSan m 25 Teachert p t diplay 1 派生類的對象可以賦值給基類對象 voidmain Teachert zhangSan m 25 assistant Personp t p diplay 派生類的對象賦值給基類對象時舍棄了派生類自己增加的成員 只是將由基類繼承而來的數據成員的值賦給基類對象的相應成員 基類的對象不能夠賦值給派生類 如下代碼錯誤Personp zhangSan m 25 Teachert p errort diplay 2 派生類的地址可以賦值給基類的指針 voidmain Teachert zhangSan m 25 assistant Personp Li

溫馨提示

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

評論

0/150

提交評論