《C++進階--10.多態》

目錄

10.?多態

10.1 多態的基本概念

10.2 多態案例一-計算器類

10.3 純虛函數和抽象類

10.4 多態案例二-制作飲品

10.5 虛析構和純虛析構

10.6 多態案例三-電腦組裝


10.?多態

10.1 多態的基本概念

多態是C++面向對象三大特性之一

多態分為兩類

  • 靜態多態: 函數重載 和 運算符重載屬于靜態多態,復用函數名

  • 動態多態: 派生類和虛函數實現運行時多態

靜態多態和動態多態區別:

  • 靜態多態的函數地址早綁定 - 編譯階段確定函數地址

  • 動態多態的函數地址晚綁定 - 運行階段確定函數地址

示例:

class Animal
{
public://Speak函數就是虛函數//函數前面加上virtual關鍵字,變成虛函數,那么編譯器在編譯的時候就不能確定函數調用了。virtual void speak(){cout << "動物在說話" << endl;}
};
?
class Cat :public Animal
{
public:void speak(){cout << "小貓在說話" << endl;}
};
?
class Dog :public Animal
{
public:
?void speak(){cout << "小狗在說話" << endl;}
?
};
//我們希望傳入什么對象,那么就調用什么對象的函數
//如果函數地址在編譯階段就能確定,那么靜態聯編
//如果函數地址在運行階段才能確定,就是動態聯編
?
void DoSpeak(Animal & animal)
{animal.speak();
}
//
//多態滿足條件: 
//1、有繼承關系
//2、子類重寫父類中的虛函數
//多態使用:
//父類指針或引用指向子類對象
?
void test01()
{Cat cat;DoSpeak(cat);
?
?Dog dog;DoSpeak(dog);
}
?
?
int main() {
?test01();
?system("pause");
?return 0;
}

總結:

多態滿足條件

  • 有繼承關系

  • 子類重寫父類中的虛函數

多態使用條件

  • 父類指針或引用指向子類對象

重寫:函數返回值類型 函數名 參數列表 完全一致稱為重寫

10.2 多態案例一-計算器類

案例描述:

分別利用普通寫法和多態技術,設計實現兩個操作數進行運算的計算器類

多態的優點:

  • 代碼組織結構清晰

  • 可讀性強

  • 利于前期和后期的擴展以及維護

示例:

//普通實現
class Calculator {
public:int getResult(string oper){if (oper == "+") {return m_Num1 + m_Num2;}else if (oper == "-") {return m_Num1 - m_Num2;}else if (oper == "*") {return m_Num1 * m_Num2;}//如果要提供新的運算,需要修改源碼}
public:int m_Num1;int m_Num2;
};
?
void test01()
{//普通實現測試Calculator c;c.m_Num1 = 10;c.m_Num2 = 10;cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;
?cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;
?cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
}
?
?
?
//多態實現
//抽象計算器類
//多態優點:代碼組織結構清晰,可讀性強,利于前期和后期的擴展以及維護
class AbstractCalculator
{
public :
?virtual int getResult(){return 0;}
?int m_Num1;int m_Num2;
};
?
//加法計算器
class AddCalculator :public AbstractCalculator
{
public:int getResult(){return m_Num1 + m_Num2;}
};
?
//減法計算器
class SubCalculator :public AbstractCalculator
{
public:int getResult(){return m_Num1 - m_Num2;}
};
?
//乘法計算器
class MulCalculator :public AbstractCalculator
{
public:int getResult(){return m_Num1 * m_Num2;}
};
?
?
void test02()
{//創建加法計算器AbstractCalculator *abc = new AddCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;delete abc; ?//用完了記得銷毀
?//創建減法計算器abc = new SubCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;delete abc; ?
?//創建乘法計算器abc = new MulCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;delete abc;
}
?
int main() {
?//test01();
?test02();
?system("pause");
?return 0;
}

總結:C++開發提倡利用多態設計程序架構,因為多態優點很多

10.3 純虛函數和抽象類

在多態中,通常父類中虛函數的實現是毫無意義的,主要都是調用子類重寫的內容

因此可以將虛函數改為純虛函數

純虛函數語法:virtual 返回值類型 函數名 (參數列表)= 0 ;

當類中有了純虛函數,這個類也稱為抽象類

抽象類特點

  • 無法實例化對象

  • 子類必須重寫抽象類中的純虛函數,否則也屬于抽象類

示例:

class Base
{
public://純虛函數//類中只要有一個純虛函數就稱為抽象類//抽象類無法實例化對象//子類必須重寫父類中的純虛函數,否則也屬于抽象類virtual void func() = 0;
};
?
class Son :public Base
{
public:virtual void func() {cout << "func調用" << endl;};
};
?
void test01()
{Base * base = NULL;//base = new Base; // 錯誤,抽象類無法實例化對象base = new Son;base->func();delete base;//記得銷毀
}
?
int main() {
?test01();
?system("pause");
?return 0;
}

10.4 多態案例二-制作飲品

案例描述:

制作飲品的大致流程為:煮水 - 沖泡 - 倒入杯中 - 加入輔料

利用多態技術實現本案例,提供抽象制作飲品基類,提供子類制作咖啡和茶葉

示例:

//抽象制作飲品
class AbstractDrinking {
public://燒水virtual void Boil() = 0;//沖泡virtual void Brew() = 0;//倒入杯中virtual void PourInCup() = 0;//加入輔料virtual void PutSomething() = 0;//規定流程void MakeDrink() {Boil();Brew();PourInCup();PutSomething();}
};
?
//制作咖啡
class Coffee : public AbstractDrinking {
public://燒水virtual void Boil() {cout << "煮農夫山泉!" << endl;}//沖泡virtual void Brew() {cout << "沖泡咖啡!" << endl;}//倒入杯中virtual void PourInCup() {cout << "將咖啡倒入杯中!" << endl;}//加入輔料virtual void PutSomething() {cout << "加入牛奶!" << endl;}
};
?
//制作茶水
class Tea : public AbstractDrinking {
public://燒水virtual void Boil() {cout << "煮自來水!" << endl;}//沖泡virtual void Brew() {cout << "沖泡茶葉!" << endl;}//倒入杯中virtual void PourInCup() {cout << "將茶水倒入杯中!" << endl;}//加入輔料virtual void PutSomething() {cout << "加入枸杞!" << endl;}
};
?
//業務函數
void DoWork(AbstractDrinking* drink) {drink->MakeDrink();delete drink;
}
?
void test01() {DoWork(new Coffee);cout << "--------------" << endl;DoWork(new Tea);
}
?
?
int main() {
?test01();
?system("pause");
?return 0;
}

10.5 虛析構和純虛析構

多態使用時,如果子類中有屬性開辟到堆區,那么父類指針在釋放時無法調用到子類的析構代碼

解決方式:將父類中的析構函數改為虛析構或者純虛析構

虛析構和純虛析構共性:

  • 可以解決父類指針釋放子類對象

  • 都需要有具體的函數實現

虛析構和純虛析構區別:

  • 如果是純虛析構,該類屬于抽象類,無法實例化對象

虛析構語法:

virtual ~類名(){}

純虛析構語法:

virtual ~類名() = 0;

類名::~類名(){}

示例:

class Animal {
public:
?Animal(){cout << "Animal 構造函數調用!" << endl;}virtual void Speak() = 0;
?//析構函數加上virtual關鍵字,變成虛析構函數//virtual ~Animal()//{//  cout << "Animal虛析構函數調用!" << endl;//}
?
?virtual ~Animal() = 0;
};
?
Animal::~Animal()
{cout << "Animal 純虛析構函數調用!" << endl;
}
?
//和包含普通純虛函數的類一樣,包含了純虛析構函數的類也是一個抽象類。不能夠被實例化。
?
class Cat : public Animal {
public:Cat(string name){cout << "Cat構造函數調用!" << endl;m_Name = new string(name);}virtual void Speak(){cout << *m_Name << ?"小貓在說話!" << endl;}~Cat(){cout << "Cat析構函數調用!" << endl;if (this->m_Name != NULL) {delete m_Name;m_Name = NULL;}}
?
public:string *m_Name;
};
?
void test01()
{Animal *animal = new Cat("Tom");animal->Speak();
?//通過父類指針去釋放,會導致子類對象可能清理不干凈,造成內存泄漏//怎么解決?給基類增加一個虛析構函數//虛析構函數就是用來解決通過父類指針釋放子類對象delete animal;
}
?
int main() {
?test01();
?system("pause");
?return 0;
}

總結:

1. 虛析構或純虛析構就是用來解決通過父類指針釋放子類對象

2. 如果子類中沒有堆區數據,可以不寫為虛析構或純虛析構

3. 擁有純虛析構函數的類也屬于抽象類

10.6 多態案例三-電腦組裝

案例描述:

電腦主要組成部件為 CPU(用于計算),顯卡(用于顯示),內存條(用于存儲)

將每個零件封裝出抽象基類,并且提供不同的廠商生產不同的零件,例如Intel廠商和Lenovo廠商

創建電腦類提供讓電腦工作的函數,并且調用每個零件工作的接口

測試時組裝三臺不同的電腦進行工作

示例:

#include<iostream>
using namespace std;
?
//抽象CPU類
class CPU
{
public://抽象的計算函數virtual void calculate() = 0;
};
?
//抽象顯卡類
class VideoCard
{
public://抽象的顯示函數virtual void display() = 0;
};
?
//抽象內存條類
class Memory
{
public://抽象的存儲函數virtual void storage() = 0;
};
?
//電腦類
class Computer
{
public:Computer(CPU * cpu, VideoCard * vc, Memory * mem){m_cpu = cpu;m_vc = vc;m_mem = mem;}
?//提供工作的函數void work(){//讓零件工作起來,調用接口m_cpu->calculate();
?m_vc->display();
?m_mem->storage();}
?//提供析構函數 釋放3個電腦零件~Computer(){
?//釋放CPU零件if (m_cpu != NULL){delete m_cpu;m_cpu = NULL;}
?//釋放顯卡零件if (m_vc != NULL){delete m_vc;m_vc = NULL;}
?//釋放內存條零件if (m_mem != NULL){delete m_mem;m_mem = NULL;}}
?
private:
?CPU * m_cpu; //CPU的零件指針VideoCard * m_vc; //顯卡零件指針Memory * m_mem; //內存條零件指針
};
?
//具體廠商
//Intel廠商
class IntelCPU :public CPU
{
public:virtual void calculate(){cout << "Intel的CPU開始計算了!" << endl;}
};
?
class IntelVideoCard :public VideoCard
{
public:virtual void display(){cout << "Intel的顯卡開始顯示了!" << endl;}
};
?
class IntelMemory :public Memory
{
public:virtual void storage(){cout << "Intel的內存條開始存儲了!" << endl;}
};
?
//Lenovo廠商
class LenovoCPU :public CPU
{
public:virtual void calculate(){cout << "Lenovo的CPU開始計算了!" << endl;}
};
?
class LenovoVideoCard :public VideoCard
{
public:virtual void display(){cout << "Lenovo的顯卡開始顯示了!" << endl;}
};
?
class LenovoMemory :public Memory
{
public:virtual void storage(){cout << "Lenovo的內存條開始存儲了!" << endl;}
};
?
?
void test01()
{//第一臺電腦零件CPU * intelCpu = new IntelCPU;VideoCard * intelCard = new IntelVideoCard;Memory * intelMem = new IntelMemory;
?cout << "第一臺電腦開始工作:" << endl;//創建第一臺電腦Computer * computer1 = new Computer(intelCpu, intelCard, intelMem);computer1->work();delete computer1;
?cout << "-----------------------" << endl;cout << "第二臺電腦開始工作:" << endl;//第二臺電腦組裝Computer * computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);;computer2->work();delete computer2;
?cout << "-----------------------" << endl;cout << "第三臺電腦開始工作:" << endl;//第三臺電腦組裝Computer * computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);;computer3->work();delete computer3;
?
}

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

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

相關文章

全網爆火的 MBTI 測試,是隱藏的割韭菜工具?

小伙伴們&#xff0c;誰能想到&#xff0c;作為一名沖浪老手&#xff0c;果子在網上又被騙了。 事情是這樣的&#xff0c;前幾天&#xff0c;我刷微博&#xff0c;看到一個推薦&#xff0c;大概如下圖&#xff0c;是一個 MBTI 人格測試。 MBTI 測試&#xff0c;果子早就做過了…

UCSF DOCK 分子對接詳細案例(01)- rigid, fixed anchor, flexible dock

歡迎瀏覽我的CSND博客&#xff01; Blockbuater_drug …點擊進入 文章目錄 前言一、操作環境二、研究背景三、受體-配體結構文件準備3.1準備文件夾DOCK_workdir, 下載晶體結構3.1.1 來自濕實驗的受體配體共晶結構&#xff1a;3.1.2 來自深度學習和語言模型推理預測的蛋白結構&a…

Spring Boot整合Kafka

文章目錄 1. 介紹2. Kafka基礎2.1. 安裝KafKakafka集群搭建_kafka交流群-CSDN博客 3. Spring Boot整合Kafka3.1. 引入Kafka依賴3.2.編寫配置文件 4. 生產者&#xff08;produced&#xff09;4.1. 生產者基礎案例(基礎測試) 5. 消費者5.1.消費者基本案例(基礎測試) 6.Kafka常用配…

【LLM RAG】GritLM:統一嵌入和生成的大語言模型淺談

前言 目前&#xff0c;所有基于文本的語言問題都可以歸結為生成問題&#xff0c;并通過單一的LLM來處理。然而&#xff0c;使用嵌入的任務&#xff08;如聚類或檢索&#xff09;在這種視角下往往被忽視了。文本嵌入在許多關鍵的實際應用中扮演著重要角色。如RAG&#xff0c;在…

AIGC下一步:如何用AI再度重構或優化媒體處理?

讓媒資中“沉默的大多數”再次煥發光彩。 鄒娟&#xff5c;演講者 編者按 AIGC時代下&#xff0c;媒體內容生產領域隨著AI的出現也涌現出更多的變化與挑戰。面對AI的巨大沖擊&#xff0c;如何優化或重構媒體內容生產技術架構&#xff1f;在多樣的應用場景中媒體內容生產技術又…

Oracle case when end和decode的區別

Oracle中的CASE WHEN和DECODE都是條件表達式&#xff0c;但它們在某些方面有所不同。 CASE WHEN&#xff1a; CASE WHEN是一個條件表達式&#xff0c;允許您基于條件返回不同的值。它具有以下結構&#xff1a; sql CASE WHEN condition1 THEN result1 WHEN condition2 THE…

JavaScript 基本數據類型的詳解

JavaScript的基本數據類型 以下都是JS內置的幾種類型 數據類型描述number數字&#xff0c;不區分整數和小數string字符串類型booleantrue 真, false 假undefined表示未定義的值null只有唯一的值 null&#xff0c;表示空值 number 數字類型 JavaScript 中不區分整數和浮點數&…

itertools, 一個超好用的Python庫

前言 Python用來處理迭代器的工具你想到了啥&#xff1f;itertools 就是一個特別有用的庫&#xff0c;它提供了一系列用于創建和操作迭代器的工具&#xff0c;以下是10個常用的操作&#xff0c;可用在實際工作中&#xff0c;熟練掌握這些操作&#xff0c;將極大提升你在 Pytho…

棧(順序棧)實現Language C

###王道考研的學習領悟&#xff0c;個人喜好講解清晰 何為棧&#xff1f; 定義:棧&#xff08;stack&#xff09;是只允許在一端進行插入或刪除的線性表。 其重要術語&#xff1a;棧頂&#xff0c;棧底&#xff0c;空棧。 我們只需要把這個圖看明白了&#xff0c;理解起來就…

學校機房Dev c++解決中文亂碼問題

工具->編譯選項->勾選 編譯時加入以下命令 -fexec-charsetGBK -finput-charsetUTF-8 顯示中文&#xff1a;工具->編輯器選項->去掉第一個的勾勾。

vue+node對接支付寶沙箱

目錄 一、準備工作 二、后端node 1、添加支付寶配置文件 2、開始寫支付提交接口 3、前端部分&#xff08;點擊提交訂單&#xff09;3.1、寫axios請求 3.2、點擊提交訂單按鈕后發送網絡請求 3.3、付款成功跳轉的頁面的路徑是下面這樣的&#xff1a; 4、后端向支付寶發請求…

Github上最值得學習的10個Android開源項目,安卓面試題

1.Java語言進階與Android相關技術核 Android應用是由Java語言進行開發的&#xff0c;SDK也是由Java語言編寫&#xff0c;對于Android來說&#xff0c;只要SDK沒有用Kotlin重寫&#xff0c;那么Java語言是都需要學習的。而且Android APK的后臺服務器程序大概率是Java語言構建&a…

【計算機網絡】應用層自定義協議

自定義協議 一、為什么需要自定義協議&#xff1f;二、網絡版計算器1. 基本要求2. 序列化和反序列化3. 代碼實現&#xff08;1&#xff09;封裝 socket&#xff08;2&#xff09;定制協議和序列化反序列化&#xff08;3&#xff09;客戶端&#xff08;4&#xff09;計算器服務端…

Javaweb之SpringBootWeb案例之自動配置以及常見方案的詳細解析

3.2 自動配置 我們講解了SpringBoot當中起步依賴的原理&#xff0c;就是Maven的依賴傳遞。接下來我們解析下自動配置的原理&#xff0c;我們要分析自動配置的原理&#xff0c;首先要知道什么是自動配置。 3.2.1 概述 SpringBoot的自動配置就是當Spring容器啟動后&#xff0c…

OLLAMA 本地模型調用

Ollama 網址下載 再cmd&#xff0c;用 library 里面的庫 英文對話&#xff1a; Gemma is available in both 2b and 7b parameter sizes: ollama run gemma:2bollama run gemma:7b (default) 中文對話 ollama run qwen:0.5bollama run qwen:1.8b 用vscode而不是cmd調用 …

【論文筆記】An Effective Adversarial Attack on Person Re-Identification ...

原文標題&#xff08;文章標題處有字數限制&#xff09;&#xff1a; 《An Effective Adversarial Attack on Person Re-Identification in Video Surveillance via Dispersion Reduction》 Abstract 通過減少神經網絡內部特征圖的分散性攻擊reid模型。 erbloo/Dispersion_r…

強化學習嵌入Transformer(代碼實踐)

這里寫目錄標題 ChatGPT的答案GPT4.0 ChatGPT的答案 # 定義Transformer模塊 class Transformer(nn.Module):def __init__(self, input_dim, hidden_dim, num_heads, num_layers):super(Transformer, self).__init__()self.encoder_layer nn.TransformerEncoderLayer(d_modeli…

Vue3中組件通訊的方式

Vue3中組件通訊的方式 1 &#x1f916;GPT&#x1f916;: (答案有點問題混淆了vue2的內容) 父組件向子組件傳遞數據 props 子組件通過 props 屬性從父組件接收數據。emit事件子組件通過emit 事件 子組件通過 emit事件子組件通過emit 發射事件向父組件發送消息。provide / in…

Java SpringCloud gateway面試題

Java SpringCloud gateway面試題 前言1、什么是網關Zuul&#xff08;gateway&#xff09;&#xff1f;2、服務網關的作用&#xff1f;3、Zuul網關(Gateway)如何搭建集群&#xff1f;4、ZuulFilter常用有那些方法&#xff1f;5、如何實現動態zuul網關路由轉發&#xff1f;6、在Z…

kubeadm安裝部署

目錄 1.要求 2.環境準備 3.所有節點安裝docker 4.所有節點安裝kubeadm&#xff0c;kubelet和kubectl 5.部署K8S集群 6.測試 7.擴展3個副本 8.部署Dashboard master&#xff08;2C/4G&#xff0c;cpu核心數要求大于2&#xff09;192.168.27.10docker、kubeadm、kubelet、…