c++|多態

c++|多態

  • 1 多態的概念
  • 2 多態的定義及其實現
  • 2.1 滿足多態的條件
  • 2.2 虛函數
  • 2.3 虛函數的重寫
    • 2.4 析構函數適合加virtural嗎
    • 2.4 C++11 override 和 final
    • 2.5 三個概念的對比
  • 3 多態的原理
  • 4 抽象類
    • 4.1 概念
    • 4.2 純虛函數

1 多態的概念

多態的概念:通俗來說,就是多種形態,具體點就是去完成某個行為,當不同的對象去完成時會產生出不同的狀態。

2 多態的定義及其實現

```cpp
class Person {
public:virtual void BuyTicket() { cout << "買票-全價" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "買票-半價" << endl; }/*注意:在重寫基類虛函數時,派生類的虛函數在不加virtual關鍵字時,雖然也可以構成重寫(因為繼承后基類的虛函數被繼承下來了在派生類依舊保持虛函數屬性),但是該種寫法不是很規范,不建議這樣使用*//*void BuyTicket() { cout << "買票-半價" << endl; }*/
};
void Func(Person& p)
{p.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
}

2.1 滿足多態的條件

那么在繼承中要構成多態還有兩個條件:

  1. 必須通過基類的指針或者引用調用虛函數
  2. 被調用的函數必須是虛函數,且派生類必須對基類的虛函數進行重寫

2.2 虛函數

即被virtural修飾的類成員函數

2.3 虛函數的重寫

虛函數的重寫(覆蓋):派生類中有一個跟基類完全相同的虛函數(即派生類虛函數與基類虛函數的
返回值類型、函數名字、參數列表完全相同),稱子類的虛函數重寫了基類的虛函數。
有兩個例外

  1. 協變(基類與派生類虛函數返回值類型不同)
    基類虛函數返回基類對象的指針或者引用,派生類虛函數返回派生類對象的指針或者引用時,稱為協變。(了解)

  2. 如果基類的析構函數為虛函數,此時派生類析構函數只要定義,無論是否加virtual關鍵字,
    都與基類的析構函數構成重寫,雖然基類與派生類析構函數名字不同。雖然函數名不相同,
    看起來違背了重寫的規則,其實不然,這里可以理解為編譯器對析構函數的名稱做了特殊處理,編譯后析構函數的名稱統一處理成destructor

協變

class Person {
public:virtual A* f() { cout << "Person: " << endl;return new A; }
};
class Student : public Person {
public:virtual B* f() { cout << "Student:" << endl;;return new B; }
};
void Func(Person& p) 
{p.f();
}
int main()
{Person p;Student s;Func(p);Func(s);return 0;
}

2.4 析構函數適合加virtural嗎

class Person {
public:~Person() {cout << "~Person" << endl;}
};class Student : public Person {int* ptr = new int[10];
public:~Student() {delete ptr;cout << "~Student" << endl;}
};int main()
{Person * p1 = new Person();Person* p2 = new Student();// 都調用 Persondelete p1;delete p2;return 0;
}

所以我們建議加上 vitural

2.4 C++11 override 和 final

final:修飾虛函數,表示該虛函數不能再被重寫

class Car
{
public:virtual void Drive() final {}
};
class Benz :public Car
{
public:virtual void Drive() {cout << "Benz-舒適" << endl;}
};
  1. override: 檢查派生類虛函數是否重寫了基類某個虛函數,如果沒有重寫編譯報錯。
class Car{
public:virtual void Drive(){}
};
class Benz :public Car {
public:virtual void Drive() override {cout << "Benz-舒適" << endl;}
};

2.5 三個概念的對比

在這里插入圖片描述

3 多態的原理

class Person {
public:virtual void BuyTicket() { cout << "買票-全價" << endl; }int _i = 1;
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "買票-半價" << endl; }int _j = 2;
};
void Func(Person& p)
{p.BuyTicket();
}
int main()
{Person Mike;Func(Mike);Student Johnson;Func(Johnson);return 0;
}

每個有虛函數的對象,都有個一個虛函數表指針,每個虛函數都進入了虛函數表中。
在這里插入圖片描述

  1. 觀察下圖的紅色箭頭我們看到,p是指向mike對象時,p->BuyTicket在mike的虛表中找到虛
    函數是Person::BuyTicket。
  2. 觀察下圖的藍色箭頭我們看到,p是指向johnson對象時,p->BuyTicket在johson的虛表中
    找到虛函數是Student::BuyTicket。
  3. 這樣就實現出了不同對象去完成同一行為時,展現出不同的形態

滿足多態以后的函數調用,不是在編譯時確定的,是運行起來以后到對象的中取找的。不滿足多態的函數調用時編譯時確認好的。

驗證每個虛函數都進入了函數指針表中

class Base {
public:virtual void func1() { cout << "Base::func1" << endl; }virtual void func2() { cout << "Base::func2" << endl; }
private:int a;
};
class Derive :public Base {
public:virtual void func1() { cout << "Derive::func1" << endl; }virtual void func3() { cout << "Derive::func3" << endl; }virtual void func4() { cout << "Derive::func4" << endl; }
private:int b;
};
typedef void  (*VFPTR) () ;
VFPTR p2[10];
void PrintVFT(VFPTR* arr) 
{for (int i = 0; i < 4; i++) {printf("%p\n", arr[i]);VFPTR pf = arr[i];(*pf)();}}int main()
{Derive d;VFPTR* ptr = (VFPTR*)(*(int*)(&d));PrintVFT(ptr);return 0;
}

4 抽象類

4.1 概念

有純虛函數的類稱為抽象類,抽象類不能實例化。
派生類繼承后也不能實例化出對象,只有重寫純虛函數,派生類才能實例化出對象。

4.2 純虛函數

在虛函數的后面寫上 =0 ,則這個函數為純虛函數。

class Car
{
public:
virtual void Drive() = 0;
};
class Benz :public Car
{
public:virtual void Drive(){cout << "Benz-舒適" << endl;}
};
class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};
void Test()
{
Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();
}

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

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

相關文章

2413. 最小偶倍數

題目&#xff1a; 給你一個正整數 n &#xff0c;返回 2 和 n 的最小公倍數&#xff08;正整數&#xff09;。 示例 1&#xff1a; 輸入&#xff1a;n 5 輸出&#xff1a;10 解釋&#xff1a;5 和 2 的最小公倍數是 10 。 示例 2&#xff1a; 輸入&#xff1a;n 6 輸出&a…

JS 手寫 節流throttle 防抖debounce函數

防抖debounce // 手寫防抖 function debounce(fn, delay 200) {// timer 在閉包中let timer null// 返回一個函數return function(...args) {if (timer) {clearTimeout(timer) // 清空上次的值}timer setTimeout(() > {fn.apply(this, args) // 透傳 this 和函數參數},…

【再探】設計模式—代理模式

代理是指授權代理人在一定范圍內代表其向第三方進行處理有關事務。 1 代理模式 需求&#xff1a;1&#xff09;將業務代碼與非業務代碼分離&#xff0c;在不改變代碼結構的基礎上&#xff0c;為其添加新的功能。2&#xff09;為系統中的某些操作做同一處理&#xff0c;例如進…

[實例] Unity Shader 逐像素漫反射與半蘭伯特光照

漫反射光照是Unity中最基本最簡單的光照模型&#xff0c;本篇將會介紹在片元著色器中實現反射效果&#xff0c;并會采用半蘭伯特光照技術對其進行改進。 1. 逐頂點光照與逐像素光照 在Unity Shader中&#xff0c;我們可以有兩個地方可以用來計算光照&#xff1a;在頂點著色器…

數據結構:帶頭雙向循環鏈表

目錄 前言 鏈表實現 1.定義節點 2.接口實現 1.開辟新節點 2.初始化 3.打印鏈表 4.添加節點 頭插 尾插 在pos位置之前增加節點 5.刪除節點 判空 頭刪 尾刪 刪除pos位置的節點 6.查找 7.釋放 前言 帶頭雙向循環鏈表的結構最復雜&#xff0c;一般用在單獨存儲數…

z3-加法器實驗

補碼器加減法&#xff0c;運算方法簡介 我們要知道什么是補碼的加法&#xff0c;我們為什么要用補碼的加法&#xff1f; 補碼的加法其實就是將兩個補碼形式的二進制數字直接相加&#xff0c;處理的時候忽略超出固定位數的進位。補碼的加法運算和無符號二進制數的加法操作一樣&…

【最新區塊鏈論文錄用資訊】CCF A — SP 2024 共17篇

Conference&#xff1a;45th IEEE Symposium onSecurity and Privacy CCF level&#xff1a;CCF A Categories&#xff1a;網絡與信息安全 Year&#xff1a;2024 Num&#xff1a;17 Efficient Zero-Knowledge Arguments For Paillier Cryptosystem Paillier 加密系統的有效…

基于python的網頁自動刷新工具

1.下載webdriver https://msedgewebdriverstorage.z22.web.core.windows.net/?prefix122.0.2365.59/下載Edge的瀏覽器驅動 2.安裝selenium pip install selenium4.11.1 3.寫代碼 # -*- coding: utf-8 -*- import tkinter as tk from tkinter import messagebox import thr…

【halcon】set_part 實現平移和縮放 徹悟版

背景 之前寫了一篇關于set_part 的文章 &#xff0c;確實也實現了平移和縮放。平移是對的&#xff0c;但是縮放其實有畸變。這個問題一直都困擾著我&#xff0c;知道昨天連續測試了好幾個小時&#xff0c;直到晚上11點終于完美解決。 坐標和高寬 坐標 再講set_part 之前&am…

免費擼gpt-4o和各種大模型實用經驗分享

項目 Github: https://github.com/MartialBE/one-api 先貼兩張圖&#xff1a; 說明 免費擼AI大模型,各位可以對照下面我給出的大模型記錄表來填&#xff0c;key需要自己去拿&#xff0c;國內都需要手機號驗證&#xff0c;如果你不介意。另外我在自己的博客放出免費API給大家…

模型評價指標筆記:混淆矩陣+F1+PR曲線+mAP

評價指標 二分類評價指標 混淆矩陣 TP: 正確預測為了正樣本&#xff0c;原來也是正樣本 FN: 錯誤的預測為負樣本&#xff0c;原來是正樣本 (漏報&#xff0c;沒有找到正確匹配的數目) FP: 錯誤的預測為正樣本&#xff0c;原來是負樣本 (誤報&#xff0c;沒有的匹配不正確) TN…

CIM模型

CIM 是 Esri 制圖信息模型。 它是一個地圖內容規范,用于記錄在保存、讀取、引用或打開時如何永久保留描述不同項目組件的信息。 該規范以 JSON 表示,適用于 ArcGIS 應用程序和 API 中的地圖、場景、布局、圖層、符號和樣式。 CIM 不僅限于制圖設置。 要了解屬性的組織方式以及…

【Tools】SpringBoot工程中,對于時間屬性從后端返回到前端的格式問題

Catalog 時間屬性格式問題一、需求二、怎么使用 時間屬性格式問題 一、需求 對于表中時間字段&#xff0c;后端創建對應的實體類的時間屬性需要設定格式&#xff08;默認的格式不方便閱讀&#xff09;&#xff0c;再返回給前端。 二、怎么使用 導入jackson相關的坐標&#x…

Vue.js - Vue 的安裝 以及 常用的 Vue 指令 【0基礎向 Vue 基礎學習】

文章目錄 Vue 快速上手1、Vue.js 官網 & Vue.js 的獲取2、創建 Vue 實例&#xff0c;初始化渲染3、插值表達式 安裝 Vue 開發者工具&#xff1a;裝插件調試 Vue 應用Vue 指令1、v-show 指令2、v-if3、v-else & v-else-if4、v-onv-on 調用傳參 5、v-bindv-bind 對于樣式…

【算法】前綴和算法——和為k的子數組之和

題解&#xff1a;和為k的子數組之和(前綴和算法) 目錄 1.題目2.題解思路2.1前綴和 哈希表&#xff0c;算法步驟&#xff1a;2.2細節如下&#xff1a;2.3參考代碼&#xff1a; 3.總結及思考 1.題目 題目鏈接&#xff1a;LINK 2.題解思路 暴力求解自然不用多說&#xff0c;時…

【SQL】外連接 LEFT JOIN

目錄 一.內連接與外連接 1.內連接&#xff08;inner join&#xff09; 2.外連接&#xff08;outer join&#xff09; 二.兩表連接 1.我們先來試試看內連接&#xff1a; 2.我們再來試試外連接 三.單表外連接 四.總結 一.內連接與外連接 先得介紹內連接和外連接兩個概念&…

第199題|關于函數的周期性問題|函數強化訓練(六)|武忠祥老師每日一題 5月24日

解題思路&#xff1a;解這道題我們要用到下面這個結論 f(x)連續&#xff0c;以T為周期時&#xff0c;原函數以T為周期的充分必要條件是&#xff1a; (A) sin x顯然是以π為周期的&#xff0c;我們可以看到并不等于0,根據結論&#xff0c;A的原函數顯然不是周期函數。 (B) 的…

memmove使?和模擬實現

一&#xff1a;memmove的使? 這是memmove在庫里的定義&#xff0c;具體可在cplusplus.com查看 void * memmove ( void * destination, const void * source, size_t num ) ? 和memcpy的差別就是memmove函數處理的源內存塊和?標內存塊是可以重疊的。 ? 如果源空間和?標…

你以為的私域是真正的私域嘛??你的私域流量真的屬于你嘛?

大家好 我是一個軟件開發公司的產品經理 專注私域電商行業7年有余 您的私域流量是真正的屬于你自己嘛&#xff1f; 私域的定義 私域的界定&#xff1a;一個互聯網私有數據&#xff08;資產&#xff09;積蓄的載體。這個載體的數據權益私有&#xff0c;且具備用戶規則制定權…