八、重學C++—動態多態(運行期)

上一章節:

七、重學C++—靜態多態(編譯期)-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146999362?spm=1001.2014.3001.5502

本章節代碼:

cpp/dynamicPolymorphic.cpp · CuiQingCheng/cppstudy - 碼云 - 開源中國https://gitee.com/cuiqingcheng/cppstudy/blob/master/cpp/dynamicPolymorphic.cpp

目錄

上一章節:

本章節代碼:

一、引言

二、概念:什么是運行時多態?

三、實現機制:虛函數

虛函數表和虛函數表指針的作用

四、純虛函數,抽象類/接口類

抽象類

接口類

五、多態的優點和應用場景

優點

應用場景

六、總結

下一章節:


一、引言

????????在 C++ 的奇妙世界里,多態是一個強大而迷人的特性,它就像代碼世界中的變形金剛,讓程序能夠根據不同的情況展現出多樣的行為。而 運行期多態,作為多態的重要組成部分 ,更是為程序帶來了無與倫比的靈活性和擴展性。今天,我們就一起來深入探秘 C++ 運行期多態的奧秘。

二、概念:什么是運行時多態?

????????運行期多態,也被稱為 動態多態 ,是指在 程序運行時才確定具體要調用哪個函數 。它通過 虛函數和繼承機制來實現,允許我們使用基類的指針或引用調用派生類的函數,從而實現不同對象的不同行為 。簡單來說,就是在運行時 根據實際對象的類型來決定執行哪個函數 ,就像變形金剛在戰斗中根據不同的場景變換形態一樣。

三、實現機制:虛函數

????????虛函數是實現運行期多態的關鍵。在基類中,我們使用?“ virtual?關鍵字來聲明虛函數, 派生類可以重寫這些虛函數以實現自己的特定行為 。當通過基類的指針或引用調用虛函數時,程序會在運行時根據指針或引用實際指向的對象類型來決定調用哪個版本的函數。
class base{public:virtual void func() // 虛函數{ }
}class A:public base{public:void func() override {// 重寫實現虛函數        }
}
每一個 包含虛函數的類中均有一個虛函數表指針,指向虛函數表;如下圖:

虛函數表和虛函數表指針的作用

虛函數表( VTable): 每個 包含虛函數的類都有一個虛函數表,這是一個存儲虛函數地址的數組 。表中的每個條目都是一個指向虛函數的指針,這些虛函數按照它們在類中聲明的順序排列。
虛函數表指針( VPTR): 每個包含虛函數的類的對象都有一個虛函數表指針,它指向該類對應的虛函數表 。借助這個指針,對象能夠在運行時找到正確的虛函數來調用。
實例:一個動物的基類,均有叫這個實現函數,對于兩個繼承自動物類的狗類/貓類,分別實現其叫這個函數,代碼如下:
/****  C++ 多態*      動態多態*          虛函數/純虛函數*          抽象類/接口類*/#include <iostream>// 基類 Animal
class Animal {
public:// 虛函數 speak()virtual void speak() {std::cout << "動物發出聲音" << std::endl;}
};// 派生類 Cat
class Cat : public Animal {
public:// 重寫 speak() 函數void speak() override {std::cout << "喵~" << std::endl;}
};// 派生類 Dog
class Dog : public Animal {
public:// 重寫 speak() 函數void speak() override {std::cout << "汪!" << std::endl;}
};int main() {// 創建 Cat 和 Dog 對象Cat cat;Dog dog;// 使用基類指針指向派生類對象Animal* animal1 = &cat;Animal* animal2 = &dog;// 調用虛函數animal1->speak(); // 輸出:喵~animal2->speak(); // 輸出:汪!animal1->Animal::speak(); // 輸出:動物發出聲音return 0;
}
這里 基類的指針,會根據實際指向的對象類型,從而決定默認調用的是重寫的虛函數 ,若還想調用基類原來的虛函數,需要指定作為基類方可調用;

四、純虛函數,抽象類/接口類

上面定義的基類中,虛函數還是實現了,若 一個虛函數沒有實現的代碼段體,則是純虛函數,定義如下:
virtual int func() = 0;

抽象類

????????包含純虛函數的類被稱為抽象類 抽象類不能被實例化 ,只能作為基類被派生類繼承。 派生類必須重寫抽象類中的純虛函數,否則派生類也會成為抽象類。只有實現了純虛函數的派生類,才能實例化對象。

接口類

特殊的抽象類, 類中所有函數都是純虛函數
實例如下:
/****  C++ 多態*      動態多態*          虛函數/純虛函數*          抽象類/接口類*/#include <iostream>// 抽象類class Organism{
public:virtual void growup() = 0;virtual void eating(){std::cout << "eating everything" << std::endl;};};// 基類 Animal 還是抽象類,無法實例化對象
class Animal : public Organism{
public:// 虛函數 speak()virtual void speak() {std::cout << "動物發出聲音" << std::endl;}
};// 派生類 Cat
class Cat : public Animal {
public:void growup(){std::cout<< "貓越長越大" << std::endl;}// 重寫 speak() 函數void speak() override {std::cout << "喵~" << std::endl;}
};// 派生類 Dog
class Dog : public Animal {
public:void growup(){std::cout<< "狗越長越大" << std::endl;}// 重寫 speak() 函數void speak() override {std::cout << "汪!" << std::endl;}
};int main() {// 創建 Cat 和 Dog 對象Cat cat;Dog dog;// 使用基類指針指向派生類對象Animal* animal1 = &cat;Animal* animal2 = &dog;// 調用虛函數animal1->speak(); // 輸出:喵~animal2->speak(); // 輸出:汪!animal1->growup(); // 輸出:喵~animal2->growup(); // 輸出:汪!animal1->Animal::speak(); // 輸出:動物發出聲音return 0;
}

五、多態的優點和應用場景

優點

  1. 靈活性和擴展性:運行期多態允許我們在不修改現有代碼的情況下,輕松地添加新的派生類和功能
  2. 代碼復用:通過使用基類的指針或引用,我們可以編寫通用的代碼來處理不同類型的對象,從而提高代碼的復用性。例如,圖形繪制程序中,我們可以編寫一個通用的函數來計算不同圖形的面積,而不需要為每種圖形編寫單獨的函數。
  3. 可維護性:運行期多態使得代碼的結構更加清晰,易于理解和維護。通過將不同的行為封裝在不同的派生類中,我們可以避免代碼的冗余和混亂。

應用場景

  1. 游戲開發:在游戲開發中,運行期多態可以用于實現不同角色的不同行為,如攻擊、防御、移動等。例如,不同類型的角色(如戰士、法師、刺客)可以繼承自一個基類?Character,并分別重寫?attack()defend()move()?等函數,以實現不同的行為。
  2. 圖形處理:在圖形處理中,運行期多態可以用于實現不同圖形的不同繪制方法。例如,不同類型的圖形(如圓形、矩形、三角形)可以繼承自一個基類?Shape,并分別重寫?draw()?函數,以實現不同的繪制方法。
  3. 數據庫訪問:在數據庫訪問中,運行期多態可以用于實現不同數據庫的不同訪問方法。例如,不同類型的數據庫(如 MySQL、Oracle、SQLite)可以繼承自一個基類?Database并分別重寫?connect()query()insert()?等函數,以實現不同的訪問方法。

六、總結

????????運行期多態是 C++ 中一個非常強大和重要的特性,它通過虛函數和繼承機制實現了在程序運行時根據實際對象的類型來決定執行哪個函數的功能。

下一章節:

九、重學C++—類和函數-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147017358?spm=1001.2014.3001.5501

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

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

相關文章

eventEmitter實現

沒有做任何異常處理,簡單模擬實現 事件對象的每一個事件都對應一個數組 /*__events {"事件1":[cb1,cb2],"事件2":[cb3,cb4],"事件3":[...],"事件4":[...],};*/class E{__events {};constructor(){}//注冊監聽回調on(type , callbac…

Mysql 中 B 樹 vs B+ 樹

&#x1f333; 什么是 B樹 和 B樹&#xff1f; 它們都是多路平衡查找樹&#xff08;M-Way Search Tree&#xff09;&#xff0c;用于提升磁盤讀寫效率&#xff0c;常用于數據庫&#xff08;如 MySQL&#xff09;、操作系統中的索引結構。 &#x1f50d; B樹 和 B樹 的核心區別…

藍橋云客---九宮幻方

1.九宮幻方 - 藍橋云課 九宮幻方 題目描述 小明最近在教鄰居家的小朋友小學奧數&#xff0c;而最近正好講述到了三階幻方這個部分&#xff0c;三階幻方指的是將1~9不重復的填入一個3 * 3的矩陣當中&#xff0c;使得每一行、每一列和每一條對角線的和都是相同的。 三階幻方又…

OrangePi5Plus開發板不能正確識別USB 3.0 設備 (綠聯HUB和Camera)

1、先插好上電&#xff08;可正確識別&#xff09; 2、上電開機后插入USB 3.0 設備&#xff0c;報錯如下&#xff0c;只能檢測到USB2.0--480M&#xff0c;識別不到USB3.0-5Gbps&#xff0c;重新插拔也不行 Apr 4 21:30:00 orangepi5plus kernel: [ 423.575966] usb 5-1: re…

LiveData 和 MutableLiveData 的區別

LiveData 和 MutableLiveData 的區別 主要在于是否可以修改數據&#xff0c;但它們的工作原理基本相同。下面我們深入對比它們的行為、特性&#xff0c;以及它們在 ViewModel 和 UI 層中的使用方式。 1. LiveData 和 MutableLiveData 的基本區別 特性LiveDataMutableLiveData可…

SDK中窗口調用

存在窗口A和B的win32程序 , 當點擊窗口A中的按鈕后會彈出窗口B #include <windows.h>// 窗口 B 的窗口過程 LRESULT CALLBACK WindowProcB(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {switch (uMsg) {case WM_DESTROY:PostQuitMessage(0);break;default:ret…

進行性核上性麻痹:飲食調理為健康護航

進行性核上性麻痹是一種復雜的神經退行性疾病&#xff0c;目前雖無法根治&#xff0c;但合理的健康飲食有助于緩解癥狀、提高患者生活質量。 高蛋白質食物在患者飲食中占據重要地位。魚肉&#xff0c;尤其是富含 Omega-3 脂肪酸的三文魚、鱈魚等&#xff0c;不僅蛋白質含量豐富…

【Windows+Cursor】從0到1配置Arxiv MCP Server,實現論文自主查詢、下載、分析、綜述生成

1. 安裝UV Installation | uv powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" 將安裝路徑添加到環境變量 C:\Users\xxxxxx\.local\bin 2. git clone 代碼 git clone https://github.com/blazickjp/arxiv-mcp-server.git…

WPF 教程:給 TreeView 添加 SelectedItem 雙向綁定支持(MVVM-Friendly)

&#x1f332;WPF 教程&#xff1a;給 TreeView 添加 SelectedItem 雙向綁定支持&#xff08;MVVM-Friendly&#xff09; 在 WPF 的 MVVM 應用中&#xff0c;TreeView 是非常常見的控件&#xff0c;但它有個“頑固”的缺陷&#xff1a; ?它的 SelectedItem 不是依賴屬性&…

Linux環境下內存錯誤問題排查與修復

最近這幾天服務器總是掉線&#xff0c;要查一下服務器的問題。可以首先查看一下計算機硬件&#xff0c;這是一臺某魚上拼湊的服務器&#xff1a; sudo lshw -shortH/W path Device Class Description system NF5270M3 (To be filled by O…

函數和模式化——python

一、模塊和包 將一段代碼保存為應該擴展名為.py 的文件&#xff0c;該文件就是模塊。Python中的模塊分為三種&#xff0c;分別為&#xff1a;內置模塊、第三方模塊和自定義模塊。 內置模塊和第三方模塊又稱為庫內置模塊&#xff0c;有 python 解釋器自帶&#xff0c;不用單獨安…

windows下載安裝遠程桌面工具RealVNC-Server教程(RealVNC_E4_6_1版帶注冊碼)

文章目錄 前言一、下載安裝包二、安裝步驟三、使用VNC-Viewer客戶端遠程連接&#xff0c;輸入ip地址&#xff0c;密碼完成連接 前言 在現代工作和生活中&#xff0c;遠程控制軟件為我們帶來了極大的便利。RealVNC - Server 是一款功能強大的遠程控制服務器軟件&#xff0c;通過…

Android Dagger 2 框架的注解模塊深入剖析 (一)

本人掘金號&#xff0c;歡迎點擊關注&#xff1a;https://juejin.cn/user/4406498335701950 一、引言 在 Android 開發中&#xff0c;依賴注入&#xff08;Dependency Injection&#xff0c;簡稱 DI&#xff09;是一種強大的設計模式&#xff0c;它能夠有效降低代碼的耦合度&…

HTML語言的空值合并

HTML語言的空值合并 引言 在現代Web開發中&#xff0c;HTML&#xff08;超文本標記語言&#xff09;是構建網頁的基礎語言。隨著前端技術的快速發展&#xff0c;開發者們面臨著大量不同的工具和技術&#xff0c;尤其是在數據處理和用戶交互方面。空值合并是一些編程語言中常用…

【數據結構】樹的介紹

目錄 一、樹1.1什么是樹&#xff1f;1.2 樹的概念與結構1.3樹的相關術語1.4 樹形結構實際運用場景 二、二叉樹2.1 概念與結構2.2 特殊的二叉樹2.2.1 滿二叉樹2.2.2 完全二叉樹 個人主頁&#xff0c;點擊這里~ 數據結構專欄&#xff0c;點擊這里~ 一、樹 1.1什么是樹&#xff1…

Muduo網絡庫實現 [十三] - HttpRequest模塊

目錄 設計思路 成員設計 模塊實現 設計思路 首先我們要先知道HTTP的請求的流程是什么樣子的&#xff0c;不然我們會學的很迷糊。對于HTTP請求如何到來以及去往哪里&#xff0c;我們應該很清楚的知道 HTTP請求在服務器系統中的傳遞流程是一個多層次的過程: 客戶端發起請求…

6. RabbitMQ 死信隊列的詳細操作編寫

6. RabbitMQ 死信隊列的詳細操作編寫 文章目錄 6. RabbitMQ 死信隊列的詳細操作編寫1. 死信的概念2. 消息 TTL 過期(觸發死信隊列)3. 隊列超過隊列的最大長度(觸發死信隊列)4. 消息被拒(觸發死信隊列)5. 最后&#xff1a; 1. 死信的概念 先從概念上解釋上搞清楚這個定義&#…

如何使用Selenium進行自動化測試?

&#x1f345; 點擊文末小卡片 &#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 對于很多剛入門的測試新手來說&#xff0c;大家都將自動化測試作為自己職業發展的一個主要階段。可是&#xff0c;在成為一名合格的自動化測試工程師之前&#…

洛谷題單3-P5724 【深基4.習5】求極差 最大跨度值 最大值和最小值的差-python-流程圖重構

題目描述 給出 n n n 和 n n n 個整數 a i a_i ai?&#xff0c;求這 n n n 個整數中的極差是什么。極差的意思是一組數中的最大值減去最小值的差。 輸入格式 第一行輸入一個正整數 n n n&#xff0c;表示整數個數。 第二行輸入 n n n 個整數 a 1 , a 2 … a n a_1,…

STM32智能手表——任務線程部分

RTOS和LVGL我沒學過&#xff0c;但是應該能硬啃這個項目例程 ├─Application/User/Tasks # 用于存放任務線程的函數 │ ├─user_TaskInit.c # 初始化任務 │ ├─user_HardwareInitTask.c # 硬件初始化任務 │ ├─user_RunModeTasks.c…