C++ 多態性

在這里插入圖片描述

一 多態性的分類

編譯時的多態
函數重載
運算符重載
運行時的多態
虛函數

1 運算符重載的引入

使用C++編寫程序時,我們不僅要使用基本數據類型,還要設計新的數據類型-------類類型。

一般情況下,基本數據類型的運算都是運算符來表達,這很直觀,語義也簡單。

例如:

int a,b,c;a=b+c;

對于基本數據類型,就隱含著運算符重載的概念。

在這里插入圖片描述
在這里插入圖片描述
如果直接將運算符作用在類類型之上,情況又如何呢?
例如:

Complex ret,c1,c2;ret=c1+c2;

編譯器將不能識別運算符的語義。
需要一種機制來重新定義運算符作用在類類型上的含義。
這種機制就是運算符重載。

二 兩種重載函數的比較

多數情況下,運算符可以重載為類的成員函數,也可以重載為友元函數。但兩種重載也有各自特點:
一般情況下,單目運算符重載為類的成員函數;雙目元素重載為類的友元函數。
有些雙目運算符不能重載為類的友元函數:=,(),[],->
類型轉換函數只能定義為類的成員函數,而不能定義為友元函數。
若一個運算符的操作需要修改對象的狀態,則重載為成員函數比較好;
若運算符所需要的操作數(尤其是第一個操作數)希望有隱式類型轉換,則只能選擇友元函數;
若運算符是成員函數,最左邊的操作數必須是運算符類的對象(或者類對象的引用)。如果左邊操作數必須是一個不同類的對象,或者是基本數據類型,則必須重載為友元函數;
當需要重載運算符的元素具有交換性時,重載為友元函數;

1 重載運算符的幾點注意事項

大多數預定義的運算符可以被重載,重載后的優先級、結合級及所需的操作數都不變。
但少數的C++運算符不能重載:
例如:::、#、?:、.、
不能重載非運算符的符號,例如:;
C++ 不運行重載不存在的運算符,如"?"、“**”等。

當運算符被重載時,它是被綁定在一個特定的類類型之上的。當此運算符不作用在特定類類型上時,它將保持原有的含義。

當重載運算符時,不能創造新的運算符符號,例如不能用"**"來表示求幕運算符。

應當盡可能保持重載運算符原有的語義。試想,如果在某個程序中用"+“表示減,”*"表示除,那么這個程序讀起來將會非常別扭。

三 多態性的引入

1 虛函數和多態性

重載普通的成員函數的兩種方式:
在同一個類中重載:重載函數是以參數特征區分的。
派生類重載基類的成員函數:
由于重載函數處在不同的類中,因此它們的原型可以完全相同。調用時使用“類名::函數名”的方式加以區分。
以上兩種重載的匹配都是在編譯的時候靜態完成的。

重載是一種簡單形式的多態。
C++提供另一種更加靈活的多態機制:虛函數。虛函數運行函數調用與函數體的匹配在運行時才確定。
虛函數提供的是一種動態綁定的機制。

2 賦值兼容規則

在公有派生方式下,派生類對象可以作為基類對象來使用,具體方式如下:
在這里插入圖片描述

派生類擁有從基類繼承過來的成員;
基類對象和派生類對象的內存布局方式;
在這里插入圖片描述
當一個派生類對象直接賦值給基類對象時,不是所有的數據都賦給了基類對象,賦予的只是派生類對象的一部分。這部分叫做派生類對象的“切片(sliced)”。

注意
回憶一下不同的繼承方式,子類對基類中成員的訪問權限:
在這里插入圖片描述
只有在公有派生的情況下,才有可能出現“基類的公有成員變成派生類的公有成員”的情況。
在這里插入圖片描述
通過基類引用或指針所能看到的是一個基類對象,派生類中的成員對于基類引用或指針來說是“不可見的”。

我們能不能“通過基類引用或指針來訪問派生類的成員”呢?
為了達到上述目的,我們可以利用C++的虛函數機制,將基類的Print說明為虛函數形式。這樣就可以通過基類引用或指針來訪問派生類中的Print。

3 虛函數

在基類中用virtual關鍵字聲明的成員函數即為虛函數。

虛函數可以在一個或多個派生類中被重寫定義,但要求重定義時虛函數的原型(包括返回值類型、函數名、參數列表)必須完全相同。

3 基類中的函數具有虛特性的條件

在基類中用virtual將函數說明為虛函數。
在公有派生類中原型一致地重載該虛函數。
定義基類引用或指針,使其引用或指向派生類對象。當通過該引用或指針調用需要函數時,該函數將體現出虛特性來。

C++中,基類必須指出希望派生類重定義哪些函數。定義為virtual的函數是基類期待派生類重新定義的,基類希望派生類繼承的函數不能定義為虛函數。

注意:
在派生類中重載虛函數時必須與基類中的函數原型相同,否則該函數將丟失虛特性。

僅返回類型不同,其他相同。C++編譯器認為這種情況是不允許的。

函數原型不同,,僅函數名相同。C++編譯器認為這是一般的函數重載,此時虛特性丟失。

四 虛函數與多態性

1 提供虛函數的意義

提升軟件的重用性
基類使用虛函數提供一個接口,但派生類可以定義自己的實現版本。
虛函數調用的解釋依賴于它的對象類型,這就實現了“一個接口,多種語義”的概念。
提供軟件架構的合理性。

2 虛函數和虛指針

在編譯時,為每個有虛函數的類建立一張虛函數表VTABLE,表中存放的時每一個虛函數的指針;同時用一個虛指針VPTR指向這張表的入口。
訪問某個虛函數時,不是直接找到那個函數的地址,而是通過VPTR間接查到它的地址。

在這里插入圖片描述
在這里插入圖片描述
對象的內存空間除了保存數據成員外,還保存VPTR。VPTR由構造函數來初始化。

3 對虛函數的要求

虛函數必須是類的非靜態成員函數。
不能將虛函數說明為全局函數。
不能將虛函數說明為靜態成員函數。
不能將虛函數說明為友元函數。

本質的原因就是非靜態成員函數隱含傳遞this指針,而通過this指針能夠找到VPTR。

4 在成員函數中調用虛函數

在一個基類或派生類的成員函數中,可以直接調用類等級中的虛函數。此時需要根據成員函數中this指針所指向的對象來判斷調用的時哪一個函數。

5 析構函數可以定義為虛函數

構造函數不能定義為虛函數。
而析構函數可以定義為虛函數。

若析構函數為虛函數,那么當使用delete釋放基類指針所指向的派生類對象時,先調用派生類的析構函數,再調用基類的析構函數。

五 純虛函數與抽象類

在這里插入圖片描述

基類中的這些公共接口只需要有售賣而不需要有實現,即純虛函數。純虛函數刻畫了派生類應該遵循的協議,這些協議的具體實現由派生類來決定。

在這里插入圖片描述
將一個函數說明為純虛hasn’t,就要求任何派生類都定義自己的實現。
擁有純虛函數的類被稱為抽象類。抽象類不能被實例化,只能作為基類被使用。
抽象類的派生類需要實現純虛函數,否則該派生類也是一個抽象類。
當抽象類的所有函數成員都是純虛函數時,這個類被稱為接口類。

小結:
繼承和動態綁定在兩個方面簡化了我們的程序:
能夠容易地定義與其他類相似但又不相同的新類,能更容易地編寫忽略這些相似類型之間區別的程序。

許多應用程序的特性可以用一些相關但略有不同的概率描述。面向對象編程與這種應用非常匹配。通過繼承可以定義一些類型,可以模型不同沖類;通過動態綁定可以編寫程序,使用這些類而又忽略與具體類型相關的差異。

繼承和動態綁定的思想在概念上非常簡單,但對于如何創建應用程序以及對于程序設計語言必須支持得特性,含義深遠。

面向對象編程的關鍵思想是多態性。因為在需要情況下可以互換地使用派生類型或基類型的“許多形態”,所以稱通過繼承而相關聯的類型為多態類型。C++中,多態型僅用于通過繼承而相關性的類型的引用或指針。

我們稱因繼承而相關的類構成一個繼承層次。其中一個類稱為根,所有其他類直接或間接繼承根類。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/12297.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/12297.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/12297.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C++】詳解C++的模板

目錄 概念 ?編輯 語法 函數模板 類模板 非類型模板參數 模板的特化 函數模板特化 類模板特化 全特化 偏特化 分離編譯 概念 模板是C中非常厲害的設計,模板把通用的邏輯剝離出來,讓不同的數據類型可以復用同一種模板的邏輯,甚至可以…

Flutter 中的 DataTable 小部件:全面指南

Flutter 中的 DataTable 小部件:全面指南 在Flutter的Material組件庫中,DataTable是一個用于展示數據的表格組件,它允許開發者以一種結構化和可滾動的方式展示數據集。DataTable非常適合展示詳細信息,如表格數據、統計數據或配置…

PHP黑魔法之md5繞過

php本身是一種弱語言,這個特性決定了它的兩個特點: 輸入的參數都是當作字符串處理變量類型不需要聲明,大部分時候都是通過函數進行類型轉化php中的判斷有兩種: 松散比較:只需要值相同即可,類型不必相同,不通類型比較會先轉化為同類型,比如全數字字符串和數字比較,會比…

凸優化理論學習三|凸優化問題(一)

系列文章目錄 凸優化理論學習一|最優化及凸集的基本概念 凸優化理論學習二|凸函數及其相關概念 文章目錄 系列文章目錄一、優化問題(一)標準形式的優化問題(二)可行點和最優點(三)局部最優點(四…

《Python編程從入門到實踐》day28

# 昨日知識點回顧 安裝Matplotlib 繪制簡單的折線圖 # 今日知識點學習 15.2.1 修改標簽文字和線條粗細 # module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? # 解決辦法:matplotlib切換圖形界面顯示終端TkAgg。 #…

使用Three.js繪制快速而逼真的水

本文將利用GPUComputationRenderer來實現水波紋的繪制,相似的案例可以看threejs官方的GPGPU Water示例。更多精彩內容盡在數字孿生平臺。 什么是 GPGPU GPGPU代表通用圖形處理單元(General-Purpose Graphic Processing Unit),意思…

1146 -Table ‘performance schema.session variables‘ doesn‘t exist的錯誤解決

一、問題出現 今天在本地連數據庫的時候,發現這個問題,哎呦我擦,差點嚇死了 二、解決辦法 1)找文件 用everything搜一下MySQL Server 5.7 然后去Windows服務找一下MySQL配置文件的具體路徑 如果知道那最好,不知道那…

寶塔8.1.0去除綁定用戶

非要綁定手機號,確實很煩 1,/www/server/panel/BTPanel __init__.py if not public.is_bind():return redirect(/bind, 302) 將is_bind的路由全部注釋 2,/www/server/panel/class下 panelPlugin.py 注釋異常, 新增 softLis…

SSL協議

SSL 安全傳輸協議(安全套接層) 也叫TLS ---- 傳輸層安全協議 SSL的工作原理:SSL協議因為是基于TCP協議工作的,通信雙方需要先建立TCP會話。因為SSL協議需要進行安全保證,需要協商安全參數,所以也需要建立…

【MySQL】7.MySQL性能優化的六大核心策略

數據庫的性能對整個應用的響應速度和用戶體驗起著至關重要的作用。MySQL,作為廣泛使用的開源關系型數據庫,提供了豐富的性能優化手段。從資源優化、查詢優化到結構、配置、代碼乃至架構優化,每一個層面的調整都可能帶來性能的飛躍。本文將深入…

springboot房屋租賃系統

摘要 房屋租賃系統;為用戶提供了一個房屋租賃系統平臺,方便管理員查看及維護,并且可以通過需求進行設備信息內容的編輯及維護等;對于用戶而言,可以隨時進行查看房屋信息和合同信息,并且可以進行報修、評價…

清理緩存簡單功能實現

在程序開發中,經常會用到緩存,最常用的后端緩存技術有Redis、MongoDB、Memcache等。 而有時候我們希望能夠手動清理緩存,點一下按鈕就把當前Redis的緩存和前端緩存都清空。 功能非常簡單,創建一個控制器類CacheController&#xf…

SpringBoot PowerMockito 私有/靜態/方法/屬性

SpringBoot PowerMockito 私有/靜態/方法/屬性 1 PrepareForTest2 待測試類3 測試類 1 PrepareForTest PrepareForTest 是 PowerMockito 提供的一個注解,用于告訴 PowerMockito 哪些類需要被修改以允許使用 PowerMockito 的功能。 PowerMockito 主要用于修改 Java…

【計算機畢業設計】基于SSM+Vue的線上旅行信息管理系統【源碼+lw+部署文檔+講解】

目錄 1 緒論 1.1 研究背景 1.2 設計原則 1.3 論文組織結構 2 系統關鍵技術 2.1JSP技術 2.2 JAVA技術 2.3 B/S結構 2.4 MYSQL數據庫 3 系統分析 3.1 可行性分析 3.1.1 技術可行性 3.1.2 操作可行性 3.1.3 經濟可行性 3.1.4 法律可行性 3.2系統功能分析 3.2.1管理員功能分析 3.2.…

JavaScript精粹(一)

JavaScript(簡稱為JS)是一種廣泛應用于網頁開發的腳本語言,具有以下幾個主要作用: 網頁交互:JavaScript 可以用于創建動態的網頁效果,例如響應用戶的操作,實現頁面內容的動態更新,以…

Java SE vs Java EE:深入剖析及面試指南

Java 平臺提供了多個版本來滿足不同應用場景的需求,其中最常用的是 Java SE(Standard Edition)和 Java EE(Enterprise Edition)。理解這兩個版本的區別對于任何 Java 開發者都是至關重要的,尤其是在面試過程…

C++字符串細節,面試題06

文章目錄 22. 字符串22.1. 字符數組 vs 字符指針 vs 常量字符指針 vs string22.2. strcpy vs sprintf vs memcpy22.3. strlen vs length vs size vs sizeof22.4. 字符串之間的轉換22.5 其他數據類型與字符串之間的轉換22.6 字符串分割 22. 字符串 22.1. 字符數組 vs 字符指針 …

Spring整合其他技術

文章目錄 Spring整合mybatis思路分析Mybatis程序核心對象分析整合Mybatis 代碼實現 Spring整合Junit修改成警告 Spring整合mybatis 思路分析 Mybatis程序核心對象分析 上面圖片是mybatis的代碼,上述有三個對象,分別是sqlSessionFactory,sqlS…

Linux:配置客戶端自定義autofs服務

Linux:配置客戶端自定義autofs服務 修改autofs的主策略文件 [rootserver200 data]# vim /etc/auto.master# 修改內容如下 /misc /etc/auto.misc # 掛載目錄的上級目錄 /mnt /etc/auto.timinglee --timeout3修改autofs的自定義策略文件 [rootserver200 data]…

數據庫SQL編寫規范-SQL書寫規范整理(SQL語句書寫規范全解-Word原件)

編寫本文檔的目的是保證在開發過程中產出高效、格式統一、易閱讀、易維護的SQL代碼。 1 編寫目 2 SQL書寫規范 3 SQL編寫原則 軟件全套精華資料包清單部分文件列表: 工作安排任務書,可行性分析報告,立項申請審批表,產品需求規格說…