C++虛函數多態

class C{
public:void x1(){};void x2(){};};C c;
cout << sizeof(c) <<"\n";1字節
class D{
public:void x1(){};void x2(){};virtual void x3(){};//void *vptr看不見的虛函數表指針
};
D d;
cout << sizeof(d) <<"\n";8字節

類A中,定義了一個虛函數,編譯器就會生成一個看不見的成員變量(虛函數表指針)占用一定字節。類中至少存在一個虛函數時,編譯時,就會為這個類生成一個虛函數表vtbl,經過編譯、鏈接,類和虛函數表都會保存到可執行文件中,執行時會被裝載到內存中。

在編譯期間,帶有虛函數的類會在編譯期間安插一個賦值語句(看不到)

vptr=&A::vftable;

這樣就使vptr指向vtbl。

class A{
public://void *vptr看不見的虛函數表指針void func1(){};void func2(){};virtual void vfunc1(){};virtual void vfunc2(){};virtual ~A(){};
private://vptr=&A::vftable;int m_a;int m_b;
};A a;
cout << sizeof(a) <<"\n";16字節    //虛函數一共8字節,m_a和m_b一共8字節

image-20250620213428990

多態必須存在虛函數,沒有虛函數絕不可能存在多態

判斷有沒有多態:從代碼實現上來看,查看調用調用路線是不是利用從vptr找到vtbl,然后通過查詢vtbl來找到虛函數表的入口地址并去執行虛函數,如果是這個流程,則就是多態,否則就不是多態。

多態發生的核心條件(必須同時滿足):

  1. 通過基類指針或基類引用調用函數
  2. 調用的是虛函數
  • 調用形式:指針->虛函數引用.虛函數
class Animal {
public:virtual void speak() { cout << "Animal sound" << endl; }
};class Cat : public Animal {
public:void speak() override { cout << "Meow" << endl; }
};// 場景1:通過基類指針調用虛函數
Animal* animal = new Cat();
animal->speak();  // ?? 多態:輸出"Meow"// 場景2:通過基類引用調用虛函數
Cat kitty;
Animal& ref = kitty;
ref.speak();      // ?? 多態:輸出"Meow"
案例:
class Base
{
public:virtual void myvirfunc() {}
};
Base* pa = new Base();
pa->myvirfunc();//多態Base base;
base.myvirfunc();//不是多態Base* ybase = &base;
ybase->myvirfunc();//多態

1.程序中存在繼承關系,且父類至少有一個虛函數,但子類不強制重寫虛函數(除非是純虛函數 = 0),要觸發運行時多態(動態多態),派生類必須重寫基類的虛函數
2.必須通過父類指針或父類引用指向子類對象,才能觸發多態。
3.當通過父類指針/引用調用被重寫的虛函數時,才會表現出多態行為(動態綁定)。

image-20250623091821551

// 基類(父類)必須包含虛函數
class Base {
public:virtual void myvirfunc() {} // 虛函數聲明(virtual 關鍵字)
};
// 派生類非必須重寫普通虛函數(基類已有默認實現)。僅當基類聲明為純虛函數(virtual void func() = 0;)時,派生類必須重寫
class Derive : public Base {
public:virtual void myvirfunc() {} // 重寫虛函數(virtual 可省略,但建議保留)//C++11 后可用 override 關鍵字顯式標記重寫(如 void myvirfunc() override {})
};
//父類指針指向子類對象
Derive derive;
Base* pbase = &derive;
pbase->myvirfunc(); //Derive::myvirfunc()
//或者
Base* pbase2 = new Derive(); //釋放內存請自行釋放,在這里沒演示
pbase2->myvirfunc(); //Derive::myvirfunc()
//父類引用綁定(指向)子類對象
Derive derive2;
Base& yinbase = derive2;
yinbase.myvirfunc(); //Derive::myvirfunc()
虛析構函數
class Base {
public:virtual ~Base() {} // 必須聲明為虛析構函數!
};class Derive : public Base {
public://~Derived() {}       // 自動成為虛函數,即使不寫virtual~Derive() override {} // 但建議顯式使用 override(C++11)
};Base* pb = new Derive();
delete pb; // 正確調用 Derive::~Derive() → Base::~Base()
  • 若不聲明虛析構函數delete pb 僅調用 Base::~Base(),導致派生類資源泄漏!
  1. 虛函數表的共享機制

    • 同一類的所有對象共享同一個 vtbl(節省內存)
    • vptr 在對象構造時被初始化指向該類的 vtbl
  2. 多繼承下的 vptr

    class Derived : public Base1, public Base2 {virtual void new_func() {} 
    };
    
    • 派生類會包含多個 vptr(每個基類一個)
    • vtbl 可能包含多個子表(Thunk技術處理指針偏移)
    class Base1 {
    public:virtual void func1() { cout << "Base1::func1\n"; }virtual ~Base1() {}
    };class Base2 {
    public:virtual void func2() { cout << "Base2::func2\n"; }virtual ~Base2() {}
    };class Derived : public Base1, public Base2 {
    public:virtual void new_func() { cout << "Derived::new_func\n"; }virtual void func1() override { cout << "Derived::func1\n"; }virtual ~Derived() {}
    };
    
    1. Derived類的Base1虛函數表
    索引 | 函數類型           | 實際函數地址
    -----|--------------------|-----------------
    0    | 析構函數           | Derived::~Derived
    1    | func1()            | Derived::func1
    2    | new_func()         | Derived::new_func
    
    2. Derived類的Base2虛函數表
    索引 | 函數類型           | 實際函數地址
    -----|--------------------|-----------------
    0    | 析構函數           | Thunk to Derived::~Derived
    1    | func2()            | Base2::func2
    
    1. 每個有虛函數的基類都會有自己的vptr
    2. Derived類包含兩個vptr:一個來自Base1,一個來自Base2
    3. 派生類新增的虛函數會添加到第一個基類的虛函數表中

總結:多態性的核心邏輯

步驟關鍵操作作用
必要條件基類聲明虛函數,派生類重寫建立動態綁定基礎
橋梁搭建基類指針/引用指向派生類對象提供統一接口
多態觸發通過基類接口調用虛函數運行時動態解析實際函數地址
底層支持虛函數表(vtable)+ 虛表指針(vptr)C++ 實現動態綁定的核心機制

📌 核心結論:多態性 = 虛函數重寫 + 基類訪問派生類對象 + 通過基類接口調用函數

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

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

相關文章

新編輯器編寫指南--給自己的備忘

歡迎使用Markdown編輯器 你好&#xff01; 這是你第一次使用 Markdown編輯器 所展示的歡迎頁。如果你想學習如何使用Markdown編輯器, 可以仔細閱讀這篇文章&#xff0c;了解一下Markdown的基本語法知識。 新的改變 我們對Markdown編輯器進行了一些功能拓展與語法支持&#x…

目標檢測neck算法之MPCA和FSA的源碼實現

目標檢測neck算法之MPCA和FSA的源碼實現 使用BIBM2024 Spatial-Frequency Dual Domain Attention Network For Medical Image Segmentation的Frequency-Spatial Attention和Multi-scale Progressive Channel Attention改進neck. 接下來&#xff0c;我將講解它的源碼操作的實現…

MyBatis-Plus的3.5.7和PageHelper的那個版本對應

MyBatis-Plus的3.5.7和PageHelper的那個版本對應 根據你的知識庫中提到的信息&#xff1a; MyBatis-Plus 3.5.7 使用的是 JSqlParser 4.6 版本。PageHelper 若使用了不同版本的 JSqlParser&#xff08;如 4.7&#xff09;&#xff0c;會導致沖突。 ? 推薦對應關系 為了保證…

Apifox 6 月產品更新|支持 AI 能力、交互優化、在線文檔新增 SEO 設置、gRPC 項目支持前/后置操作

在 2025 年的 API 開發領域&#xff0c;Apifox 作為一款集 API 設計、調試、Mock 和測試于一體的協作平臺&#xff0c;已成為開發者的“得力助手”。然而&#xff0c;隨著業務需求的不斷增長&#xff0c;開發者對工具的效率和功能提出了更高的要求。6 月份&#xff0c;Apifox 推…

Acrobat JavaScript 從瀏覽器到 PDF 環境的轉換

目錄 什么是 JavaScript?JavaScript 核心語言與 Acrobat 特定 API學習 JavaScript 核心語言的挑戰瀏覽器與 Acrobat JavaScript 的關鍵差異在 Acrobat 中運行 JavaScript 代碼替代瀏覽器特定函數的方法后續學習建議什么是 JavaScript? JavaScript 最初于 1995 年作為 Netsca…

OpenCV CUDA模塊設備層-----指數運算函數exp()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 OpenCV 的 CUDA 設備端數學函數 中的一個內聯函數&#xff0c;用于在 GPU 上對 uchar1 類型&#xff08;單通道圖像像素&#xff09;執行指數運算…

C++面向對象5——C++關鍵字、構造函數與拷貝構造函數

this關鍵字 C關鍵字this的深度解析 1. this指針的本質 在C中&#xff0c;this是一個特殊的隱式指針&#xff0c;它存在于每個非靜態成員函數內部&#xff0c;指向調用該函數的當前對象。其類型為&#xff1a; 對于非const成員函數&#xff1a;ClassName* const&#xff08;…

人工智能專業:探索未來的智慧前沿

親戚家的小孩剛高考完&#xff0c;問我人工智能專業是學什么、做什么的。趁機就寫一篇吧&#xff01; 人工智能專業&#xff1a;探索未來的智慧前沿 人工智能&#xff08;Artificial Intelligence&#xff0c;簡稱AI&#xff09;無疑是當今最熱門、最具顛覆性的技術之一。它正…

618風控戰升級,瑞數信息“動態安全+AI”利劍出鞘

每年的618電商促銷季&#xff0c;都是各大電商平臺和商家的兵家必爭之地。數以億計的消費者涌入線上平臺&#xff0c;期待已久的優惠券、秒殺商品如潮水般涌現&#xff0c;海量交易在瞬間達成&#xff0c;無疑是一場商業狂歡。 然而&#xff0c;在這場狂歡背后&#xff0c;自動…

神經網絡的架構

神經網絡中的基本術語 以上圖為例&#xff0c;相關的術語描述如下&#xff1a; 最左邊的稱為輸?層&#xff0c;其中的神經元稱為輸?神經元&#xff1b;最右邊的&#xff0c;即輸出層包含有輸出神經元&#xff1b;本例中的輸出神經元只有一個&#xff1b;中間層&#xff0c;既…

安全生產監測預警系統:構筑智能化的安全防線

安全生產監測預警系統是工業安全管理的核心工具&#xff0c;它利用物聯網、大數據、人工智能等技術&#xff0c;實現對生產環境、設備運行和人員行為的全方位監測&#xff0c;確保風險早發現、早預警、早處置。其核心功能涵蓋實時監測、智能預警、應急處置、數據分析與優化等多…

Java練習題精選6-10

Java練習題精選6-10 一、第六題二、第七題第八題第九題第十題 一、第六題 如何將兩個變量的值進行交換&#xff1f;假設變量a1&#xff0c;b2。 public class Main {public static void main(String[] args) {int a 1;int b 2;int tmp;System.out.println("交換前a&qu…

【GESP】C++四級考試大綱知識點梳理, (2) 結構體和二維數組

GESP C四級官方考試大綱中&#xff0c;共有11條考點&#xff0c;本文針對第2條考點進行分析介紹。 &#xff08;2&#xff09;掌握 C結構體、二維及多維數組的基本概念及使用 四級其他考點回顧&#xff1a; 【GESP】C四級考試大綱知識點梳理, (1) 指針 全文詳見&#xff1a;【G…

自動化測試--App自動化之項目實戰腳本編寫及封裝流程

1.App測試范圍 app自動化測試主要核心測試手機程序 測試方面&#xff1a; 功能測試 安裝卸載測試 升級測試 兼容性測試 網絡切換&#xff0c;中斷測試 橫豎屏切換 健壯性 2.測試環境的搭建 需要配置的環境 java jdk Java的環境 Android sdk 安卓環境 python環境…

【Unity】什么是前向渲染、延遲渲染、單通道渲染、多通道渲染?

好的&#xff0c;我們來深入剖析這些核心渲染概念&#xff0c;理解它們的原理、優缺點以及在Unity&#xff08;特別是URP&#xff09;中的應用。 核心概念&#xff1a;渲染路徑 (Rendering Path) 渲染路徑決定了光照和著色在場景中是如何計算和應用的。它定義了物體被繪制到屏…

OpenCV CUDA模塊設備層-----GPU上執行線程安全的 “原子取最大值” 操作函數

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 這是一個 OpenCV 的 CUDA 模塊&#xff08;cv::cudev&#xff09; 中封裝的原子操作函數&#xff0c;用于在 GPU 上執行線程安全的 “原子取最大…

【nRF52832】【環境搭建 1】【ubuntu下搭建nRF52832開發環境】

本文講述如何在 ubuntu 22.04 下開發 nRF52832. host 環境說明: $ uname -a Linux leo 6.8.0-60-generic #63~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 22 19:00:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux1. 安裝軟件 sudo apt install gcc-arm-none-eabisudo apt-get i…

【Nginx】403 Forbidden錯誤

當 Nginx 代理配置出現 403 Forbidden 錯誤時&#xff0c;通常是由于權限或配置問題導致。以下是常見原因和解決方案&#xff1a; 常見原因及解決方法 1. 后端服務器拒絕訪問 原因&#xff1a;后端 HTTPS 服務配置了 IP 白名單或訪問控制解決&#xff1a; 檢查后端服務器&…

詳解 `pip install -e .` 命令【PythonLinux】

詳解 pip install -e . 命令 pip install -e . 是 Python 開發中一個非常有用的命令&#xff0c;用于以"可編輯"或"開發"模式安裝當前目錄中的 Python 包。 命令分解 pip: Python 的包管理工具install: pip 的子命令&#xff0c;用于安裝包-e: 是 --edi…

將VSCode的配置遷移到Cursor

目錄 方式一&#xff1a;一鍵導入配置 1.適用場景 2.導入前的配置 3.導入步驟 4.查看導入效果 5.原理 6.注意 方式二&#xff1a;手動遷移配置文件 1.使用場景 2.導入步驟 3.注意 方式一&#xff1a;一鍵導入配置 1.適用場景 VSCode和Cursor這兩個編輯器&#xff0…