最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++之多態(tài)(一個接口多種實現(xiàn)方式)

 更新時間:2025年09月18日 08:42:05   作者:MzKyle  
C++多態(tài)分靜態(tài)(重載)與動態(tài)(虛函數(shù)),動態(tài)依賴虛函數(shù)表和虛指針實現(xiàn)運行時綁定,重寫需滿足函數(shù)簽名一致,純虛函數(shù)構(gòu)建抽象類,多態(tài)提升代碼靈活性與擴展性,但需注意析構(gòu)函數(shù)虛化及虛函數(shù)表開銷

C++的多態(tài)(Polymorphism)是面向?qū)ο缶幊蹋∣OP)的三大核心特性之一(另外兩個是封裝和繼承),其核心思想是一個接口,多種實現(xiàn),即同一操作作用于不同對象時,可產(chǎn)生不同的執(zhí)行結(jié)果。

多態(tài)讓代碼更靈活、可擴展,是構(gòu)建復雜系統(tǒng)的重要工具。

一、多態(tài)的分類

C++的多態(tài)分為兩類:靜態(tài)多態(tài)(編譯時多態(tài))和動態(tài)多態(tài)(運行時多態(tài)),二者的核心區(qū)別在于“確定調(diào)用哪個函數(shù)的時機”——前者在編譯期確定,后者在運行期確定。

1. 靜態(tài)多態(tài)(編譯時多態(tài))

靜態(tài)多態(tài)是通過函數(shù)重載運算符重載實現(xiàn)的,編譯器在編譯階段根據(jù)函數(shù)的參數(shù)列表(類型、數(shù)量、順序)或運算符的操作數(shù)類型,確定具體要調(diào)用的函數(shù)。

示例:函數(shù)重載實現(xiàn)靜態(tài)多態(tài)

#include <iostream>
using namespace std;

// 重載:同一作用域內(nèi),函數(shù)名相同,參數(shù)列表不同
int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {  // 參數(shù)類型不同
    return a + b;
}

int add(int a, int b, int c) {  // 參數(shù)數(shù)量不同
    return a + b + c;
}

int main() {
    cout << add(1, 2) << endl;       // 調(diào)用int add(int, int)
    cout << add(1.5, 2.5) << endl;   // 調(diào)用double add(double, double)
    cout << add(1, 2, 3) << endl;    // 調(diào)用int add(int, int, int)
    return 0;
}

編譯器在編譯時會根據(jù)實參的類型和數(shù)量,自動匹配到對應的重載函數(shù),這就是靜態(tài)多態(tài)的體現(xiàn)。

2. 動態(tài)多態(tài)(運行時多態(tài))

動態(tài)多態(tài)是C++多態(tài)的核心,它通過繼承+虛函數(shù)實現(xiàn),函數(shù)的具體調(diào)用在程序運行時才確定,而非編譯時。這種機制讓基類的指針/引用可以靈活指向不同派生類對象,并調(diào)用對應派生類的實現(xiàn)。

核心條件

  • 必須存在繼承關(guān)系(基類與派生類);
  • 基類中聲明虛函數(shù)(用virtual關(guān)鍵字修飾);
  • 派生類重寫(override)基類的虛函數(shù)(函數(shù)名、參數(shù)列表、返回值必須完全一致,協(xié)變返回類型除外);
  • 通過基類的指針或引用調(diào)用虛函數(shù)。

二、動態(tài)多態(tài)的實現(xiàn)原理

動態(tài)多態(tài)的核心是虛函數(shù)表(vtable)虛指針(vptr),這是編譯器在背后自動實現(xiàn)的機制。

1. 虛函數(shù)表(vtable)

  • 當一個類中聲明了虛函數(shù)(或繼承了虛函數(shù)),編譯器會為該類生成一個虛函數(shù)表(本質(zhì)是一個函數(shù)指針數(shù)組),存儲該類所有虛函數(shù)的地址。
  • 若派生類重寫了基類的虛函數(shù),派生類的虛函數(shù)表中會用自己的函數(shù)地址覆蓋基類對應虛函數(shù)的地址;未重寫的虛函數(shù),地址仍指向基類的實現(xiàn)。

2. 虛指針(vptr)

  • 每個含有虛函數(shù)的類的對象,都會隱含一個虛指針(vptr),指向該類的虛函數(shù)表(vtable)。
  • 當通過基類指針/引用調(diào)用虛函數(shù)時,程序會通過對象的vptr找到對應的vtable,再從vtable中取出函數(shù)地址并調(diào)用,這個過程在運行時完成(動態(tài)綁定)。

示例:動態(tài)多態(tài)的直觀體現(xiàn)

#include <iostream>
using namespace std;

// 基類:形狀
class Shape {
public:
    // 虛函數(shù):繪制
    virtual void draw() {  // 用virtual聲明為虛函數(shù)
        cout << "繪制基礎(chǔ)形狀" << endl;
    }
    
    // 虛析構(gòu)函數(shù)(避免內(nèi)存泄漏)
    virtual ~Shape() {}
};

// 派生類:圓形(繼承Shape)
class Circle : public Shape {
public:
    // 重寫基類的draw()
    void draw() override {  // override關(guān)鍵字顯式聲明重寫(C++11)
        cout << "繪制圓形" << endl;
    }
};

// 派生類:矩形(繼承Shape)
class Rectangle : public Shape {
public:
    // 重寫基類的draw()
    void draw() override {
        cout << "繪制矩形" << endl;
    }
};

// 統(tǒng)一接口:接收基類引用,調(diào)用draw()
void render(Shape& shape) {
    shape.draw();  // 運行時根據(jù)實際對象類型,調(diào)用對應draw()
}

int main() {
    Circle circle;
    Rectangle rectangle;
    
    render(circle);    // 輸出:繪制圓形(實際是Circle對象)
    render(rectangle); // 輸出:繪制矩形(實際是Rectangle對象)
    
    // 基類指針指向派生類對象
    Shape* shape1 = new Circle();
    Shape* shape2 = new Rectangle();
    
    shape1->draw();  // 輸出:繪制圓形
    shape2->draw();  // 輸出:繪制矩形
    
    delete shape1;   // 虛析構(gòu)函數(shù)確保派生類析構(gòu)被調(diào)用
    delete shape2;
    return 0;
}

運行機制解析

  • Shape類有虛函數(shù)draw(),編譯器為其生成vtable,存儲Shape::draw()的地址。
  • CircleRectangle繼承Shape重寫draw(),它們的vtable中,draw()的地址被替換為各自的實現(xiàn)(Circle::draw()Rectangle::draw())。
  • render函數(shù)接收CircleRectangle對象的引用時(本質(zhì)是基類引用指向派生類對象),調(diào)用draw()時會通過對象的vptr找到對應vtable,最終執(zhí)行派生類的實現(xiàn)——這就是運行時多態(tài)。

三、重寫(Override)的細節(jié)

派生類重寫基類虛函數(shù)時,必須滿足以下條件(否則可能變成“隱藏”而非“重寫”):

函數(shù)名、參數(shù)列表完全相同:參數(shù)的類型、數(shù)量、順序必須一致(若參數(shù)不同,會變成派生類的新函數(shù),隱藏基類函數(shù))。

返回值類型相同:除非是“協(xié)變返回類型”(即基類虛函數(shù)返回基類指針/引用,派生類重寫函數(shù)返回派生類指針/引用)。

class Base {};
class Derived : public Base {};

class A {
public:
    virtual Base* func() { return new Base(); }  // 基類返回Base*
};

class B : public A {
public:
    Derived* func() override { return new Derived(); }  // 派生類返回Derived*(協(xié)變)
};

基類函數(shù)必須是虛函數(shù):若基類函數(shù)未用virtual修飾,派生類即使同名同參,也只是“隱藏”基類函數(shù),而非重寫(無法觸發(fā)多態(tài))。

訪問權(quán)限不影響多態(tài):即使派生類重寫的函數(shù)是private,通過基類指針/引用調(diào)用時仍能正常觸發(fā)(因為訪問權(quán)限檢查在編譯期,多態(tài)調(diào)用在運行期)。

四、純虛函數(shù)與抽象類

為了強制派生類必須實現(xiàn)某些功能(如“所有形狀都必須能繪制”),C++引入純虛函數(shù)抽象類

  • 純虛函數(shù):在虛函數(shù)聲明后加=0,表示該函數(shù)沒有默認實現(xiàn),必須由派生類重寫。
  • 抽象類:包含純虛函數(shù)的類(或繼承純虛函數(shù)且未重寫的類),不能實例化對象,只能作為基類被繼承。

示例:抽象類與純虛函數(shù)

class Shape {
public:
    // 純虛函數(shù):強制派生類實現(xiàn)draw()
    virtual void draw() = 0;  // =0表示純虛函數(shù)
    
    virtual ~Shape() {}  // 抽象類也需要虛析構(gòu)
};

class Circle : public Shape {
public:
    void draw() override {  // 必須重寫,否則Circle也是抽象類
        cout << "繪制圓形" << endl;
    }
};

int main() {
    // Shape s;  // 錯誤:抽象類不能實例化
    Shape* shape = new Circle();  // 正確:基類指針指向派生類對象
    shape->draw();  // 輸出:繪制圓形
    delete shape;
    return 0;
}

抽象類的核心作用是定義“接口規(guī)范”,確保派生類遵循統(tǒng)一的行為契約(如Shape規(guī)定“必須能繪制”,所有派生類都必須實現(xiàn)draw())。

五、多態(tài)的應用與優(yōu)勢

  1. 提高代碼復用性:通過基類接口統(tǒng)一處理不同派生類對象(如render函數(shù)無需為每個形狀單獨實現(xiàn))。
  2. 增強擴展性:新增派生類(如Triangle)時,無需修改現(xiàn)有接口代碼(如render),只需實現(xiàn)draw()即可,符合“開閉原則”(對擴展開放,對修改關(guān)閉)。
  3. 模擬現(xiàn)實世界的多樣性:現(xiàn)實中同一行為(如“繪制”)作用于不同對象(圓、矩形)會有不同結(jié)果,多態(tài)完美映射這種關(guān)系。

六、注意事項

析構(gòu)函數(shù)建議聲明為虛函數(shù):當通過基類指針刪除派生類對象時,若基類析構(gòu)不是虛函數(shù),會只調(diào)用基類析構(gòu)而不調(diào)用派生類析構(gòu),導致內(nèi)存泄漏。

class Base {
public:
    ~Base() { cout << "Base析構(gòu)" << endl; }  // 非虛析構(gòu)(危險)
};

class Derived : public Base {
public:
    ~Derived() { cout << "Derived析構(gòu)" << endl; }
};

int main() {
    Base* p = new Derived();
    delete p;  // 僅輸出"Base析構(gòu)",Derived析構(gòu)未調(diào)用(內(nèi)存泄漏)
    return 0;
}

解決:將基類析構(gòu)聲明為virtual ~Base() {},確保派生類析構(gòu)被調(diào)用。

避免在構(gòu)造/析構(gòu)函數(shù)中調(diào)用虛函數(shù):構(gòu)造派生類對象時,先調(diào)用基類構(gòu)造函數(shù),此時對象的動態(tài)類型仍為基類,調(diào)用虛函數(shù)會執(zhí)行基類版本;析構(gòu)時同理,可能導致不符合預期的結(jié)果。

虛函數(shù)表的開銷:每個含虛函數(shù)的類會增加vtable(靜態(tài)開銷),每個對象會增加vptr(動態(tài)內(nèi)存開銷,通常為4/8字節(jié)),但相比多態(tài)帶來的靈活性,這種開銷通??山邮?。

C++的多態(tài)通過“靜態(tài)多態(tài)(重載)”和“動態(tài)多態(tài)(虛函數(shù))”實現(xiàn),其中動態(tài)多態(tài)是核心,依賴虛函數(shù)表和虛指針實現(xiàn)運行時綁定。它讓代碼更靈活、可擴展,是構(gòu)建大型面向?qū)ο笙到y(tǒng)的基礎(chǔ)。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++類重載函數(shù)的function和bind使用示例

    C++類重載函數(shù)的function和bind使用示例

    這篇文章主要介紹了C++類重載函數(shù)的function和bind使用示例,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下
    2021-01-01
  • 簡述C++的復雜性

    簡述C++的復雜性

    這篇文章主要介紹了簡述C++的復雜性,幫助大家更好的理解和認識c++編程語言,感興趣的朋友可以了解下
    2020-08-08
  • C語言自定義軍旗游戲源碼

    C語言自定義軍旗游戲源碼

    這篇文章主要為大家詳細介紹了C語言自定義軍旗游戲源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • C++?線段樹原理與實現(xiàn)示例詳解

    C++?線段樹原理與實現(xiàn)示例詳解

    這篇文章主要為大家介紹了C++?線段樹原理與實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • C語言實現(xiàn)猜數(shù)字小游戲

    C語言實現(xiàn)猜數(shù)字小游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • C++ 中封裝的含義和簡單實現(xiàn)方式

    C++ 中封裝的含義和簡單實現(xiàn)方式

    這篇文章主要介紹了C++ 中封裝的含義和簡單實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C語言掃雷詳細代碼分步實現(xiàn)流程

    C語言掃雷詳細代碼分步實現(xiàn)流程

    掃雷是電腦上很經(jīng)典的游戲,特意去網(wǎng)上玩了一會,幾次調(diào)試之后,發(fā)現(xiàn)這個比三子棋要復雜一些,尤其是空白展開算法上和堵截玩家有的一拼,與實際游戲差別較大,不能使用光標,下面來詳解每一步分析
    2022-02-02
  • VSCode配置C/C++環(huán)境的最新詳細教程

    VSCode配置C/C++環(huán)境的最新詳細教程

    VisualStudioCode(簡稱VSCode)是Microsoft開發(fā)的代碼編輯器,它支持Windows,Linux和macOS等操作系統(tǒng)以及開源代碼,下面這篇文章主要給大家介紹了關(guān)于VSCode配置C/C++環(huán)境的最新詳細教程,需要的朋友可以參考下
    2022-12-12
  • 詳解C語言的預處理效果

    詳解C語言的預處理效果

    這篇文章主要為大家介紹了C語言的預處理效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • C++常用的#include頭文件總結(jié)

    C++常用的#include頭文件總結(jié)

    這篇文章主要介紹了C++常用的#include頭文件,對初學者理解C++程序設(shè)計大有好處的相關(guān)資料
    2014-07-07

最新評論

枣阳市| 邢台市| 扶沟县| 定州市| 宝清县| 清水河县| 泗阳县| 新泰市| 柳江县| 阿瓦提县| 洱源县| 那坡县| 普定县| 郧西县| 台安县| 昆明市| 玉环县| 镇坪县| 彭泽县| 新竹市| 祁东县| 成安县| 普安县| 松江区| 盐边县| 清苑县| 龙游县| 湛江市| 巍山| 辉县市| 布尔津县| 广安市| 天气| 伊春市| 郑州市| 陇川县| 阿拉尔市| 台南市| 积石山| 柏乡县| 张家口市|