C清華大學出版社第四版課件第八章.ppt
《C清華大學出版社第四版課件第八章.ppt》由會員分享,可在線閱讀,更多相關《C清華大學出版社第四版課件第八章.ppt(54頁珍藏版)》請在裝配圖網上搜索。
1 第八章多態(tài)性 東華理工大學信息工程學院 C 語言程序設計 2 本章主要內容 多態(tài)性運算符重載虛函數純虛函數抽象類深度探索 3 多態(tài)性的概念 多態(tài)性是面向對象程序設計的重要特征之一 多態(tài)性是指發(fā)出同樣的消息被不同類型的對象接收時有可能導致完全不同的行為 多態(tài)的實現 函數重載運算符重載虛函數 4 問題舉例 復數的運算 classComplex 復數類聲明public Complex doubler 0 0 doublei 0 0 real r imag i voiddisplay const 顯示復數的值private doublereal doubleimag 運算符重載 5 問題舉例 復數的運算 用 能夠實現復數的加減運算嗎 實現復數加減運算的方法 重載 運算符 運算符重載 6 運算符重載的實質 運算符重載是對已有的運算符賦予多重含義必要性C 中預定義的運算符其運算對象只能是基本數據類型 而不適用于用戶自定義類型 如類 實現機制將指定的運算表達式轉化為對運算符函數的調用 運算對象轉化為運算符函數的實參 編譯系統對重載運算符的選擇 遵循函數重載的選擇原則 運算符重載 7 運算符重載 規(guī)則和限制 可以重載C 中除下列運算符外的所有運算符 只能重載C 語言中已有的運算符 不可臆造新的 不改變原運算符的優(yōu)先級和結合性 不能改變操作數個數 經重載的運算符 其操作數中至少應該有一個是自定義類型 8 兩種形式 重載為類的非靜態(tài)成員函數重載為非成員函數 運算符重載 9 運算符函數 聲明形式函數類型operator運算符 形參 重載為類成員函數時參數個數 原操作數個數 1 后置 除外 重載為非成員函數時參數個數 原操作數個數 且至少應該有一個自定義類型的形參 運算符重載 10 運算符成員函數的設計 雙目運算符B如果要重載B為類成員函數 使之能夠實現表達式oprd1Boprd2 其中oprd1為A類對象 則B應被重載為A類的成員函數 形參類型應該是oprd2所屬的類型 經重載后 表達式oprd1Boprd2相當于oprd1 operatorB oprd2 運算符重載 11 運算符重載 例8 1 將 運算重載為復數類的成員函數 規(guī)則 實部和虛部分別相加減 操作數 兩個操作數都是復數類的對象 includeusingnamespacestd classComplex 復數類定義public 外部接口Complex doubler 0 0 doublei 0 0 real r imag i 構造函數Complexoperator constComplex 12 ComplexComplex operator constComplex 創(chuàng)建一個臨時無名對象作為返回值 13 voidComplex display const cout real imag endl intmain 主函數Complexc1 5 4 c2 2 10 c3 定義復數類的對象cout c1 c1 display cout c2 c2 display c3 c1 c2 使用重載運算符完成復數減法cout c3 c1 c2 c3 display c3 c1 c2 使用重載運算符完成復數加法cout c3 c1 c2 c3 display return0 14 程序輸出的結果為 c1 5 4 c2 2 10 c3 c1 c2 3 6 c3 c1 c2 7 14 15 16 運算符成員函數的設計 前置單目運算符U如果要重載U為類成員函數 使之能夠實現表達式Uoprd 其中oprd為A類對象 則U應被重載為A類的成員函數 無形參 經重載后 表達式Uoprd相當于oprd operatorU 運算符重載 17 運算符成員函數的設計 后置單目運算符 和 如果要重載 或 為類成員函數 使之能夠實現表達式oprd 或oprd 其中oprd為A類對象 則 或 應被重載為A類的成員函數 且具有一個int類型形參 經重載后 表達式oprd 相當于oprd operator 0 運算符重載 18 例8 2 運算符前置 和后置 重載為時鐘類的成員函數 前置單目運算符 重載函數沒有形參 對于后置單目運算符 重載函數需要有一個整型形參 操作數是時鐘類的對象 實現時間增加1秒鐘 運算符重載 includeusingnamespacestd classClock 時鐘類聲明定義public 外部接口Clock inthour 0 intminute 0 intsecond 0 voidshowTime const Clock 19 前置單目運算符重載函數Clock 20 后置單目運算符重載ClockClock operator int 注意形參表中的整型參數Clockold this this 調用前置 運算符returnold 21 其它成員函數的實現略intmain ClockmyClock 23 59 59 cout Firsttimeoutput myClock showTime cout ShowmyClock myClock showTime cout Show myClock myClock showTime return0 22 程序運行結果為 Firsttimeoutput 23 59 59ShowmyClock 23 59 59Show myClock 0 0 1 23 24 運算符非成員函數的設計 函數的形參代表依自左至右次序排列的各操作數 后置單目運算符 和 的重載函數 形參列表中要增加一個int 但不必寫形參名 如果在運算符的重載函數中需要操作某類對象的私有成員 可以將此函數聲明為該類的友元 運算符重載 25 運算符非成員函數的設計 雙目運算符B重載后 表達式oprd1Boprd2等同于operatorB oprd1 oprd2 前置單目運算符B重載后 表達式Boprd等同于operatorB oprd 后置單目運算符 和 重載后 表達式oprdB等同于operatorB oprd 0 運算符重載 26 例8 3 將 雙目 重載為非成員函數 并將其聲明為復數類的友元 兩個操作數都是復數類的常引用 將 雙目 重載為非成員函數 并將其聲明為復數類的友元 它的左操作數是std ostream引用 右操作數為復數類的常引用 返回std ostream引用 用以支持下面形式的輸出 cout a b 該輸出調用的是 operator operator cout a b 運算符重載 includeusingnamespacestd classComplex 復數類定義public 外部接口Complex doubler 0 0 doublei 0 0 real r imag i 構造函數friendComplexoperator constComplex 27 Complexoperator constComplex 28 29 靜態(tài)綁定與動態(tài)綁定 綁定程序自身彼此關聯的過程 確定程序中的操作調用與執(zhí)行該操作的代碼間的關系 靜態(tài)綁定綁定過程出現在編譯階段 用對象名或者類名來限定要調用的函數 動態(tài)綁定綁定過程工作在程序運行時執(zhí)行 在程序運行時才確定將要調用的函數 includeusingnamespacestd classPoint public Point doublex doubley x x y y doublearea const return0 0 private doublex y classRectangle publicPoint public Rectangle doublex doubley doublew doubleh doublearea const returnw h private doublew h 靜態(tài)綁定例 30 Rectangle Rectangle doublex doubley doublew doubleh Point x y w w h h voidfun constPoint 運行結果 Area 0 31 includeusingnamespacestd classPoint public Point doublex doubley x x y y virtualdoublearea const return0 0 private doublex y classRectangle publicPoint public Rectangle doublex doubley doublew doubleh virtualdoublearea const returnw h private doublew h 其他函數同上例 動態(tài)綁定例 32 voidfun constPoint 運行結果 Area 375 33 34 虛函數 虛函數是動態(tài)綁定的基礎 是非靜態(tài)的成員函數 在類的聲明中 在函數原型之前寫virtual virtual只用來說明類聲明中的原型 不能用在函數實現時 具有繼承性 基類中聲明了虛函數 派生類中無論是否說明 同原型函數都自動為虛函數 本質 不是重載聲明而是覆蓋 調用方式 通過基類指針或引用 執(zhí)行時會根據指針指向的對象的類 決定調用哪個函數 虛函數 35 例8 4 includeusingnamespacestd classBase1 基類Base1定義public virtualvoiddisplay const 虛函數 voidBase1 display const cout Base1 display endl classBase2 publicBase1 公有派生類Base2定義public voiddisplay const 覆蓋基類的虛函數 voidBase2 display const cout Base2 display endl 虛函數 公有派生類Derived定義classDerived publicBase2 public voiddisplay const 覆蓋基類的虛函數 voidDerived display const coutdisplay 對象指針 成員名 36 intmain 主函數Base1base1 定義Base1類對象Base2base2 定義Base2類對象Derivedderived 定義Derived類對象fun 運行結果 Base1 display Base2 display Derived display 37 38 虛析構函數 為什么需要虛析構函數 可能通過基類指針刪除派生類對象 如果你打算允許其他人通過基類指針調用對象的析構函數 通過delete這樣做是正常的 就需要讓基類的析構函數成為虛函數 否則執(zhí)行delete的結果是不確定的 虛函數 39 抽象類 帶有純虛函數的類稱為抽象類 class類名 virtual類型函數名 參數表 0 純虛函數 純虛函數與抽象類 40 抽象類 純虛函數與抽象類 作用抽象類為抽象和設計的目的而聲明 將有關的數據和行為組織在一個繼承層次結構中 保證派生類具有要求的行為 對于暫時無法實現的函數 可以聲明為純虛函數 留給派生類去實現 注意抽象類只能作為基類來使用 不能聲明抽象類的對象 構造函數不能是虛函數 析構函數可以是虛函數 41 例8 5 純虛函數與抽象類 includeusingnamespacestd classBase1 基類Base1定義public virtualvoiddisplay const 0 純虛函數 classBase2 publicBase1 公有派生類Base2定義public voiddisplay const 覆蓋基類的虛函數cout Base2 display endl classDerived publicBase2 公有派生類Derived定義public voiddisplay const 覆蓋基類的虛函數cout Derived display endl voidfun Base1 ptr ptr display 對象指針 成員名 intmain 主函數Base2base2 定義Base2類對象Derivedderived 定義Derived類對象fun 運行結果 Base2 display Derived display 42 多態(tài)類型與非多態(tài)類型 多態(tài)類型與非多態(tài)類型有虛函數的類類型稱為多態(tài)類型其它類型皆為非多態(tài)類型二者的差異語言層面的差異多態(tài)類型支持運行時類型識別多態(tài)類型對象占用額外的空間設計原則上的差異 43 深度探索 設計原則 多態(tài)類型多態(tài)類型的析構函數一般應為虛函數非多態(tài)類型非多態(tài)類型不宜作為公共基類由于沒有利用動態(tài)多態(tài)性 一般可以用組合 而無需用共有繼承 如果繼承 則由于析構函數不是虛函數 刪除對象時所執(zhí)行操作與指針類型有關 易引起混亂 把不需被繼承的類型設定為非多態(tài)類型由于成員函數都是靜態(tài)綁定 調用速度較快 對象占用空間較小 44 深度探索 運行時類型識別 運行時類型識別允許在運行時通過基類指針 或引用 辨別對象所屬的具體派生類 只對多態(tài)類型適用 比虛函數動態(tài)綁定的開銷更大 因此應僅對虛函數無法解決的問題使用 運行時類型識別的方式用dynamic cast做類型轉換的嘗試 用typeid直接獲取類型信息 45 深度探索 dynamic cast的使用 語法形式dynamic cast 表達式 功能將基類指針轉換為派生類指針 將基類引用轉換為派生類引用 轉換是有條件的如果指針 或引用 所指對象的實際類型與轉換的目的類型兼容 則轉換成功進行 否則如執(zhí)行的是指針類型的轉換 則得到空指針 如執(zhí)行的是引用類型的轉換 則拋出異常 46 深度探索 例8 9dynamic cast示例 includeusingnamespacestd classBase public virtualvoidfun1 cout Base fun1 endl virtual Base classDerived1 publicBase public virtualvoidfun1 cout Derived1 fun1 endl virtualvoidfun2 cout Derived1 fun2 endl classDerived2 publicDerived1 public virtualvoidfun1 cout Derived2 fun1 endl virtualvoidfun2 cout Derived2 fun2 endl 47 深度探索 voidfun Base b b fun1 嘗試將b轉換為Derived1指針Derived1 d dynamic cast b 判斷轉換是否成功if d 0 d fun2 intmain Baseb fun 運行結果 Base fun1 Derived1 fun1 Derived1 fun2 Derived2 fun1 Derived2 fun2 48 typeid的使用 語法形式typeid 表達式 typeid 類型說明符 功能獲得表達式或類型說明符的類型信息表達式有多態(tài)類型時 會被求值 并得到動態(tài)類型信息 否則 表達式不被求值 只能得到靜態(tài)的類型信息 類型信息用type info對象表示type info是typeinfo頭文件中聲明的類 typeid的結果是type info類型的常引用 可以用type info的重載的 操作符比較兩類型的異同 type info的name成員函數返回類型名稱 類型為constchar 49 深度探索 例8 10typeid示例 include includeusingnamespacestd classBase public virtual Base classDerived publicBase 50 深度探索 voidfun Base b 得到表示b和 b類型信息的對象consttype info 運行結果 typeid b classBase typeid b classBaseAbaseclass typeid b classBase typeid b classDerived 51 虛函數動態(tài)綁定的實現原理 動態(tài)選擇被執(zhí)行的函數函數的調用 需要通過函數代碼的入口地址把函數入口地址作為變量 在不同情況下賦予不同的值 通過該變量調用函數 就可動態(tài)選擇被執(zhí)行的函數回顧 第6章介紹的函數指針 指向成員函數的指針虛表每個多態(tài)類有一個虛表 virtualtable 虛表中有當前類的各個虛函數的入口地址每個對象有一個指向當前類的虛表的指針 虛指針vptr 動態(tài)綁定的實現構造函數中為對象的虛指針賦值通過多態(tài)類型的指針或引用調用成員函數時 通過虛指針找到虛表 進而找到所調用的虛函數的入口地址通過該入口地址調用虛函數 52 深度探索 53 classBase public virtualvoidf virtualvoidg private inti classDerived publicBase public virtualvoidf 覆蓋Base fvirtualvoidh 新增的虛函數private intj 深度探索 54 小結與復習建議 主要內容多態(tài)性的概念 運算符重載 虛函數 純虛函數 抽象類達到的目標理解多態(tài)的概念 學會運用多態(tài)機制 實驗任務實驗八- 配套講稿:
如PPT文件的首頁顯示word圖標,表示該PPT已包含配套word講稿。雙擊word圖標可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設計者僅對作品中獨創(chuàng)性部分享有著作權。
- 關 鍵 詞:
- 清華大學出版社 第四 課件 第八
裝配圖網所有資源均是用戶自行上傳分享,僅供網友學習交流,未經上傳用戶書面授權,請勿作他用。
鏈接地址:http://www.hcyjhs8.com/p-6330331.html