C++多型之虛擬函式
- Copyright(C)原文來自GitHub賬號,此為副本,僅為學習,如有侵權請聯絡刪除!
C++多型之虛擬函式
多型性
指的是相同物件在收到不同訊息或者不同物件收到相同訊息產生不同的實現動作。 C++中多型可以分為兩種:靜態多型
和動態多型
。其中靜態多型
主要的實現方式就是通過過載,過載又可以分為函式過載和運算子過載,內容比較多,這篇文章裡不會做過分詳細的描述。而動態過載
的主要實現方式就是虛擬函式
,因為虛擬函式體現了繼承和多型兩大特性, 可以說虛擬函式是C++中最重要的概念之一,正因有了虛擬函式我們才可以做到通過統一的訪問方式動態呼叫不同類中相同的函式。 雖然本文不會去描述過載的細節,但是為了對C++三大特性之一的多型性
有比較深刻的認識,還是很有必要好好比較一番過載和虛擬函式(重寫)的異同的,接下來我將逐條羅列二者的區別。
虛擬函式(重寫
):
- 1.範圍:有繼承關係的多個類中的同名函式。
- 2.引數:函式的函式名、引數均相同。
- 3.修飾符:被過載的函式必須有 virtual 修飾。
函式過載
:
- 1.範圍:位於同一個類中的同名函式。
- 2.引數:函式引數列表必須不同。
- 3.修飾符:virtual 修飾符可有可無。
比較完二者的區別,接下來把重心回到虛擬函式中來,我們必須需要知道什麼是虛擬函式, 虛擬函式是怎麼使用的,虛擬函式的實現原理以及虛擬函式和純虛擬函式的比較。
虛擬函式
的主要工作
無論是基類還是派生類,其中同名但又體現不同特性的成員函式可以通過統一的基類指標訪問。我們舉個簡單的例子,定義賬單類(作為基類),類中成員函式 print
可以列印出每個月的賬單,現有計算機學院賬單類繼承了賬單類,同樣定義了成員函式 print
,且這個函不僅僅只有函式名,連返回值和引數列表均和賬單類中的 print
函式完全相同,唯一的區別就是要額外列印出計算機學院的名字。若定義指標指向基類物件(賬單類)的指標 p
,之後用這個指標取計算機學院物件的地址,之後用 p
呼叫 print
函式,這裡本意是取得派生類物件的地址,之後呼叫可以列印出計算機學院名字的那個 print
函式。但事與願違,這裡只能呼叫基類的 print
函式,確實是使用了基類的函式列印了計算機類賬單的變數,但很顯然不是我們所想的樣子。
- 最簡單的
解決方法
就是重新定義一個指標,指標是指向計算機學院賬單物件的,這樣當我們使用這個指標訪問print
函式時,就能精確的呼叫該派生類中的print
函式了(即可以列印出計算機學院名字)。但是這種方式在程式很大的時候會造成管理十分混亂,程式設計師需要同時記得很多指標以及指標型別,這樣給程式開發維護帶來了很大的困難。 另一種解決方案
更加簡單粗暴,可以直接將各個函式中同名的函式換成不同的名字,每次呼叫時候都精確給出呼叫函式的名字,從而保證準確呼叫函式。但這種方式沒能發揮物件導向程式設計統一介面的思想,同樣給開發帶來了困難。
我們渴望有一種方式,只需要定義一個指向基類的指標,之後通過這個指標呼叫任何派生類中的函式時,都能準確通過定義的物件的型別自動去找到相應的同名函式。這就是我們所要講的虛擬函式
。
繼續使用之前的例子,我們可以在基類(賬單類)中將 print
成員函式前加上 virtual
, 這樣 print
就成了虛擬函式。之後我們在通過派生出計算機賬單類的時候,該子類中的 print 函式也會是虛擬函式(無論是否顯式的加上 virtual
關鍵字)。 之後當我們使用指向基類的指標重新取得派生類的物件地址時,使用這個地址呼叫print
函式就可以列印出計算機學院的名字了,即可以立即為指標雖然是指向基類型別的,但因為重新取了新物件的地址,當執虛擬函式時就會準確呼叫取得地址的那個物件中的虛擬函式。
接下來說一下虛擬函式的原理
虛擬函式的實現
主要是因為一個指標和一張指向函式入口的表。每一個包含虛擬函式的類都包含一個指標變數(系統自動插入類的低地址處),我們叫它vptr
,所以包含虛擬函式的類是要比實際可見的大小多出一個指標變數大小的。每個類的這個指標指向一張虛擬函式表,虛擬函式表的每一個記錄是一個虛擬函式的指標。在呼叫類的建構函式時,指向此基礎類的指標此時已經變成了指向具體類的 this
指標,這樣靠此 this
指標即可得到正確的 vtable
,如此才能真正與函式進行連線,這就是動態聯編,也是虛擬函式實現多型的基本原理。
最後,比較一下虛擬函式和純虛擬函式的區別
虛擬函式之前已經說得比較明白了,我們也看到之前的例子中,所有的基類都可以定義物件,並且基類中的虛擬函式具有完整的定義,只不過它和其派生類中的其他同名函式在函式體部分略有不同。但是在現實生活中,並不是所有的基類建立出的物件都是有意義的,比如動物作為基類,其可以派生出的老虎大象類,然後用老虎大象類去定義物件是有意義的,但是動物作為物件卻沒有什麼意義。這種情況我們可以使用純虛擬函式,純虛擬函式的實現方法是在函式原型後面加“=0”
。
純虛擬函式
和虛擬函式
之前最大的區別
純虛擬函式
在基類中只有函式宣告卻沒有函式定義,它起到的僅僅是一個介面
的作用,其具體實現部分在其派生類中實現。正因純虛擬函式沒有完整的定義,所以包含純虛擬函式的基類是不能例項化
的,它只能派生
,這種不能例項化的類也被稱為抽象類
。如果其派生出的派生類中依舊沒有將純虛擬函式改寫的話,那麼它的派生類依舊是抽象類。
相關文章
- C++多型(上)——虛擬函式、虛表C++多型函式
- C++ 繼承、多型、虛擬函式C++繼承多型函式
- 虛擬函式與多型函式多型
- C++虛擬函式與多型實戰 (轉)C++函式多型
- 詳解C++中的多型和虛擬函式C++多型函式
- 虛擬函式表-C++多型的實現原理函式C++多型
- C++(虛擬函式實現多型基本原理)C++函式多型
- C++ 虛擬函式C++函式
- C++虛擬函式C++函式
- C++繼承二之虛擬函式C++繼承函式
- C++中抽象類、虛擬函式和純虛擬函式C++抽象函式
- C++中的虛擬函式與虛擬函式表 (轉)C++函式
- c++虛擬函式表C++函式
- C++虛擬函式bugC++函式
- 【C++筆記】虛擬函式(從虛擬函式表來解析)C++筆記函式
- 【C++筆記】虛擬函式(從虛擬函式概念來解析)C++筆記函式
- 我對C++中虛擬函式、純虛擬函式在實現多型中作用的一點淺薄認識 (轉)C++函式多型
- <<從0到1學C++>> 第7篇 多型性和虛擬函式C++多型函式
- 基類指標、虛純虛擬函式、多型性、虛析構指標函式多型
- C++ 介面(純虛擬函式)C++函式
- C++ 中的虛擬函式C++函式
- C++ 虛擬函式表剖析C++函式
- C++ 虛擬函式表解析C++函式
- C++之類解構函式為什麼是虛擬函式C++函式
- 虛擬函式,虛擬函式表函式
- 虛擬函式 純虛擬函式函式
- C++中虛擬函式的作用C++函式
- C++虛擬函式解析(轉載)C++函式
- 深入C++成員函式及虛擬函式表C++函式
- C++箴言:避免解構函式呼叫虛擬函式C++箴言函式
- C++ 虛擬函式和虛繼承淺析C++函式繼承
- C++繼承三之純虛擬函式pure virtual functionC++繼承函式Function
- C++虛擬函式學習總結C++函式
- C++中的虛擬函式(virtual function)C++函式Function
- C++:純虛擬函式與抽象類C++函式抽象
- C++ Daily 《3》----建構函式可否是虛擬函式C++AI函式
- 介面、虛擬函式、純虛擬函式、抽象類函式抽象
- 虛擬函式函式