C++編譯時多態和運行時多態

C++編譯時多態和運行時多態

作者:melonstreet
出處:https://www.cnblogs.com/QG-whz/p/5132745.html
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

前言

今日的C++不再是個單純的“帶類的C”語言,它已經發展成為一個多種次語言所組成的語言集合,其中泛型編程與基于它的STL是C++發展中最為出彩的那部分。在面向對象C++編程中,多態是OO三大特性之一,這種多態稱為運行期多態,也稱為動態多態;在泛型編程中,多態基于template(模板)的具現化與函數的重載解析,這種多態在編譯期進行,因此稱為編譯期多態或靜態多態。在本文中,我們將了解:

  1. 什么是運行期多態
  2. 什么是編譯期多態
  3. 它們的優缺點在哪

運行期多態

運行期多態的設計思想要歸結到類繼承體系的設計上去。對于有相關功能的對象集合,我們總希望能夠抽象出它們共有的功能集合,在基類中將這些功能聲明為虛接口(虛函數),然后由子類繼承基類去重寫這些虛接口,以實現子類特有的具體功能。典型地我們會舉下面這個例子:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-r8RIXVVw-1642570130701)(C++編譯時多態和運行時多態.assets/poly0.png)]

class Animal
{
public :virtual void shout() = 0;
};
class Dog :public Animal
{
public:virtual void shout(){ cout << "汪汪!"<<endl; }
};
class Cat :public Animal
{
public:virtual void shout(){ cout << "喵喵~"<<endl; }
};
class Bird : public Animal
{
public:virtual void shout(){ cout << "嘰喳!"<<endl; }
};int main()
{Animal * anim1 = new Dog;Animal * anim2 = new Cat;Animal * anim3 = new Bird;//藉由指針(或引用)調用的接口,在運行期確定指針(或引用)所指對象的真正類型,調用該類型對應的接口anim1->shout();anim2->shout();anim3->shout();//delete 對象...return 0;
}

運行期多態的實現依賴于虛函數機制。當某個類聲明了虛函數時,編譯器將為該類對象安插一個虛函數表指針,并為該類設置一張唯一的虛函數表,虛函數表中存放的是該類虛函數地址。運行期間通過虛函數表指針與虛函數表去確定該類虛函數的真正實現。

運行期多態的優勢還在于它使處理異質對象集合稱為可能:

//我們有個動物園,里面有一堆動物
int main()
{vector<Animal*>anims;Animal * anim1 = new Dog;Animal * anim2 = new Cat;Animal * anim3 = new Bird;Animal * anim4 = new Dog;Animal * anim5 = new Cat;Animal * anim6 = new Bird;//處理異質類集合anims.push_back(anim1);anims.push_back(anim2);anims.push_back(anim3);anims.push_back(anim4);anims.push_back(anim5);anims.push_back(anim6);for (auto & i : anims){i->shout();}//delete對象//...return 0;
}

總結:運行期多態通過虛函數發生于運行期

編譯期多態

對模板參數而言,多態是通過模板具現化和函數重載解析實現的。以不同的模板參數具現化導致調用不同的函數,這就是所謂的編譯期多態。
相比較于運行期多態,實現編譯期多態的類之間并不需要成為一個繼承體系,它們之間可以沒有什么關系,但約束是它們都有相同的隱式接口。我們將上面的例子改寫為:

class Animal
{
public :void shout() { cout << "發出動物的叫聲" << endl; };
};
class Dog
{
public:void shout(){ cout << "汪汪!"<<endl; }
};
class Cat
{
public:void shout(){ cout << "喵喵~"<<endl; }
};
class Bird
{
public:void shout(){ cout << "嘰喳!"<<endl; }
};
template <typename T>
void  animalShout(T & t)
{t.shout();
}
int main()
{Animal anim;Dog dog;Cat cat;Bird bird;animalShout(anim);animalShout(dog);animalShout(cat);animalShout(bird);getchar();
}

在編譯之前,函數模板中t.shout()調用的是哪個接口并不確定。在編譯期間,編譯器推斷出模板參數,因此確定調用的shout是哪個具體類型的接口。不同的推斷結果調用不同的函數,這就是編譯器多態。這類似于重載函數在編譯器進行推導,以確定哪一個函數被調用。

運行期多態與編譯期多態優缺點分析

運行期多態優點

  1. OO設計中重要的特性,對客觀世界直覺認識。
  2. 能夠處理同一個繼承體系下的異質類集合。

運行期多態缺點

  1. 運行期間進行虛函數綁定,提高了程序運行開銷。
  2. 龐大的類繼承層次,對接口的修改易影響類繼承層次。
  3. 由于虛函數在運行期在確定,所以編譯器無法對虛函數進行優化。
  4. 虛表指針增大了對象體積,類也多了一張虛函數表,當然,這是理所應當值得付出的資源消耗,列為缺點有點勉強。

編譯期多態優點

  1. 它帶來了泛型編程的概念,使得C++擁有泛型編程與STL這樣的強大武器。
  2. 在編譯器完成多態,提高運行期效率。
  3. 具有很強的適配性與松耦合性,對于特殊類型可由模板偏特化、全特化來處理。

編譯期多態缺點

  1. 程序可讀性降低,代碼調試帶來困難。
  2. 無法實現模板的分離編譯,當工程很大時,編譯時間不可小覷。
  3. 無法處理異質對象集合。

關于顯式接口與隱式接口

所謂的顯式接口是指類繼承層次中定義的接口或是某個具體類提供的接口,總而言之,我們能夠在源代碼中找到這個接口.顯式接口以函數簽名為中心,例如

void AnimalShot(Animal & anim)
{anim.shout();
}

我們稱shout為一個顯式接口。在運行期多態中的接口皆為顯式接口。

而對模板參數而言,接口是隱式的,奠基于有效表達式。例如:

template <typename T>
void AnimalShot(T & anim)
{anim.shout();
}

對于anim來說,必須支持哪一種接口,要由模板參數執行于anim身上的操作來決定,在上面這個例子中,T必須支持shout()操作,那么shout就是T的一個隱式接口。

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

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

相關文章

java安全(八)TransformedMap構造POC

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 上一篇構造了一個了commons-collections的demo 【傳送門】 package test.org.vulhub.Ser;import org.apache.commons.collections.Transformer; import org…

Pytorch Tutorial 使用torch.autograd進行自動微分

Pytorch Tutorial 使用torch.autograd進行自動微分 本文翻譯自 PyTorch 官網教程。 原文&#xff1a;https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html#optional-reading-tensor-gradients-and-jacobian-products 在訓練神經網絡時&#xff0c;最常使用…

TVM:編譯深度學習模型快速上手教程

TVM&#xff1a;編譯深度學習模型快速上手教程 本文將展示如何使用 Relay python 前端構建一個神經網絡&#xff0c;并使用 TVM 為 Nvidia GPU 生成一個運行時庫。 注意我們需要再構建 TVM 時啟用了 cuda 和 llvm。 TVM支持的硬件后端總覽 在本教程中&#xff0c;我們使用 cu…

TVM:設計與架構

TVM&#xff1a;設計與架構 本文檔適用于想要了解 TVM 架構和/或積極開發項目的開發人員。頁面組織如下&#xff1a; 示例編譯流程概述了 TVM 將模型的高層描述轉換為可部署模塊所采取的步驟。要開始使用&#xff0c;請先閱讀本節。 邏輯架構組件部分描述了邏輯組件。后面的部…

遞歸+回溯

遞歸-回溯 本文參考自代碼隨想錄視頻&#xff1a; https://www.bilibili.com/video/BV1cy4y167mM https://www.bilibili.com/video/BV1ti4y1L7cv 遞歸回溯理論基礎 只要有遞歸&#xff0c;就會有回溯&#xff0c;遞歸函數的下面的部分通常就是回溯的邏輯。 回溯是純暴力的搜索…

Nvidia CUDA初級教程1 CPU體系架構綜述

Nvidia CUDA初級教程1 CPU體系架構綜述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p2 講師&#xff1a;周斌 本節內容&#xff1a;了解現代CPU的架構和性能優化&#xff1a; 流水線 Pipelining分支預測 Branch Prediction超標量 Superscalar亂序執行 Out…

Nvidia CUDA初級教程2 并行程序設計概述

Nvidia CUDA初級教程2 并行程序設計概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p3 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要&#xff1f;怎么做&#xff1f;一些技術和概念 串并行計算模式 串行計算模式 常規軟件時串行的 設計運行…

Nvidia CUDA初級教程4 GPU體系架構概述

Nvidia CUDA初級教程4 GPU體系架構概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p5 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要GPU三種方法提升GPU的處理速度實際GPU的設計舉例&#xff1a; NVDIA GTX 480: FermiNVDIA GTX 680: Kepler GP…

Nvidia CUDA初級教程5 CUDA/GPU編程模型

Nvidia CUDA初級教程5 CUDA/GPU編程模型 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p6 講師&#xff1a;周斌 本節內容&#xff1a; CPU和GPU互動模式GPU線程組織模型&#xff08;需要不停強化&#xff09;GPU存儲模型基本的編程問題 CPU與GPU交互 各自…

Nvidia CUDA初級教程6 CUDA編程一

Nvidia CUDA初級教程6 CUDA編程一 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p7 講師&#xff1a;周斌 GPU架構概覽 GPU特別使用于&#xff1a; 密集計算&#xff0c;高度可并行計算圖形學 晶體管主要被用于&#xff1a; 執行計算而不是 緩存數據控制指令…

由前中后遍歷序列構建二叉樹

由前/中/后遍歷序列構建二叉樹 基礎 首先&#xff0c;我們需要知道前中后序三種深度優先遍歷二叉樹的方式的具體順序&#xff1a; 前序&#xff1a;中左右中序&#xff1a;左中右后序&#xff1a;左右中 另外&#xff0c;要知道只有中序前/后序可以唯一確定一棵二叉樹&…

手寫nms

手寫nms 計算寬高的時候加1是為什么&#xff1f; 本文總結自互聯網的多種nms實現&#xff0c;供參考&#xff0c;非博主原創&#xff0c;各原文鏈接如下&#xff0c;也建議大家動手寫一寫。 Ref&#xff1a; 淺談NMS的多種實現 目標窗口檢測算法-NMS非極大值抑制 一、fas…

目標檢測綜述

目標檢測綜述 轉自&#xff1a;https://zhuanlan.zhihu.com/p/383616728 論文參考&#xff1a;[Object Detection in 20 Years: A Survey][https://arxiv.org/abs/1905.05055] 引言 目標檢測領域發展至今已有二十余載&#xff0c;從早期的傳統方法到如今的深度學習方法&#x…

Nvidia CUDA初級教程7 CUDA編程二

Nvidia CUDA初級教程7 CUDA編程二 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p8 講師&#xff1a;周斌 本節內容&#xff1a; 內置類型和函數 Built-ins and functions線程同步 Synchronizing線程調度 Scheduling threads存儲模型 Memory model重訪 Matr…

詳解優酷視頻質量評價體系

萬字長文 | 詳解優酷視頻質量評價體系 分享嘉賓&#xff5c;李靜博士&#xff0c;阿里巴巴文娛集團資深算法專家&#xff0c;阿里巴巴大文娛摩酷實驗室視頻體驗與質量團隊負責人 整理出品&#xff5c;AICUG人工智能社區 本文地址&#xff1a;https://www.6aiq.com/article/1617…

視頻質量評價:挑戰與機遇

視頻質量評價&#xff1a;挑戰與機遇 轉自&#xff1a;https://zhuanlan.zhihu.com/p/384603663 本文整理自鵬城實驗室助理研究員王海強在LiveVideoStack線上分享上的演講。他通過自身的實踐經驗&#xff0c;詳細講解了視頻質量評價的挑戰與機遇。 文 / 王海強 整理 / LiveVi…

關于二分法的邊界問題及兩種寫法

關于二分法的邊界問題及兩種寫法 二分查找法大家很熟悉了&#xff0c;對于一個有序序列&#xff0c;我們可以通過二分查找法在 O(logN)O(logN)O(logN) 的時間內找到想要的元素。但是&#xff0c;在代碼實現的過程中&#xff0c;如果沒有仔細理解清楚&#xff0c;二分法的邊界條…

LeetCode上的各種股票最大收益

LeetCode上的各種股票最大收益 對于力扣平臺上的股票類型的題目&#xff1a; 121 買賣股票的最佳時機 122 買賣股票的最佳時機 II 123 買賣股票的最佳時機 III 124 買賣股票的最佳時機 IV 309 最佳買賣股票時機含冷凍期 714 買賣股票的最佳時機含手續費 劍指 Offer 63. …

建設專業化運維服務團隊必要性

信息系統的生命周期涵蓋&#xff1a;設計、開發、測試、部署上線、運行維護。其中&#xff0c;運行維護階段是信息系統生命周期中的關鍵環節&#xff0c;其執行效果直接影響系統是否能達到預期的運行目標。為了實現這個目標&#xff0c;我們必須建立一個以業務服務為導向的專業…

docker初探

docker初探 本文旨在介紹 docker 基本的安裝、常用命令和常見概念的辨析&#xff0c;方便新手入門和筆者日后查閱&#xff0c;大部分內容整理自互聯網&#xff0c;原出處在文中注明。 文章目錄docker初探docker安裝&#xff08;mac&#xff09;版本、信息相關命令version/info…