欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

示例:函數(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ù)類(lèi)型不同
    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;
}

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

2. 動(dòng)態(tài)多態(tài)(運(yùn)行時(shí)多態(tài))

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

核心條件

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

二、動(dòng)態(tài)多態(tài)的實(shí)現(xiàn)原理

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

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

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

2. 虛指針(vptr)

  • 每個(gè)含有虛函數(shù)的類(lèi)的對(duì)象,都會(huì)隱含一個(gè)虛指針(vptr),指向該類(lèi)的虛函數(shù)表(vtable)。
  • 當(dāng)通過(guò)基類(lèi)指針/引用調(diào)用虛函數(shù)時(shí),程序會(huì)通過(guò)對(duì)象的vptr找到對(duì)應(yīng)的vtable,再?gòu)膙table中取出函數(shù)地址并調(diào)用,這個(gè)過(guò)程在運(yùn)行時(shí)完成(動(dòng)態(tài)綁定)。

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

#include <iostream>
using namespace std;

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

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

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

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

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

運(yùn)行機(jī)制解析

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

三、重寫(xiě)(Override)的細(xì)節(jié)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

六、注意事項(xiàng)

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

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

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;
}

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

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

虛函數(shù)表的開(kāi)銷(xiāo):每個(gè)含虛函數(shù)的類(lèi)會(huì)增加vtable(靜態(tài)開(kāi)銷(xiāo)),每個(gè)對(duì)象會(huì)增加vptr(動(dòng)態(tài)內(nèi)存開(kāi)銷(xiāo),通常為4/8字節(jié)),但相比多態(tài)帶來(lái)的靈活性,這種開(kāi)銷(xiāo)通常可接受。

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

總結(jié)

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

相關(guān)文章

  • 深入講解C++中的構(gòu)造函數(shù)

    深入講解C++中的構(gòu)造函數(shù)

    這篇文章主要介紹了C++中的構(gòu)造函數(shù),是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C語(yǔ)言手把手教你實(shí)現(xiàn)貪吃蛇AI(中)

    C語(yǔ)言手把手教你實(shí)現(xiàn)貪吃蛇AI(中)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言手把手教你實(shí)現(xiàn)貪吃蛇AI的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C語(yǔ)言實(shí)現(xiàn)班級(jí)學(xué)生管理系統(tǒng)

    C語(yǔ)言實(shí)現(xiàn)班級(jí)學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)班級(jí)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語(yǔ)言 格式化讀寫(xiě)文件詳解

    C語(yǔ)言 格式化讀寫(xiě)文件詳解

    本文主要介紹C語(yǔ)言 格式化讀寫(xiě)文件,這里提供了關(guān)于格式化讀寫(xiě)文件的基本資料及實(shí)現(xiàn)示例代碼,有興趣的小伙伴可以參考下,以便理解學(xué)習(xí)
    2016-08-08
  • OpenCV實(shí)現(xiàn)簡(jiǎn)單套索工具

    OpenCV實(shí)現(xiàn)簡(jiǎn)單套索工具

    這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)簡(jiǎn)單套索工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++中的類(lèi)成員函數(shù)當(dāng)線程函數(shù)

    C++中的類(lèi)成員函數(shù)當(dāng)線程函數(shù)

    這篇文章主要介紹了C++中的類(lèi)成員函數(shù)當(dāng)線程函數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C/C++ Windows SAPI實(shí)現(xiàn)文字轉(zhuǎn)語(yǔ)音功能

    C/C++ Windows SAPI實(shí)現(xiàn)文字轉(zhuǎn)語(yǔ)音功能

    本文通過(guò)封裝Windows SAPI(Speech Application Programming Interface),提供了一個(gè)現(xiàn)代化的C++接口實(shí)現(xiàn)文字轉(zhuǎn)語(yǔ)音功能,這篇文章重點(diǎn)給大家介紹C/C++ Windows SAPI自實(shí)現(xiàn)文字轉(zhuǎn)語(yǔ)音功能,感興趣的朋友一起看看吧
    2025-02-02
  • C語(yǔ)言詳細(xì)講解位運(yùn)算符的使用

    C語(yǔ)言詳細(xì)講解位運(yùn)算符的使用

    C語(yǔ)?既具有?級(jí)語(yǔ)?的特點(diǎn),?具有低級(jí)語(yǔ)?的特性,如?持位運(yùn)算就是其具體體現(xiàn)。這是因?yàn)?,C語(yǔ)?最初是為取代匯編語(yǔ)?設(shè)計(jì)系統(tǒng)軟件?設(shè)計(jì)的,因此C語(yǔ)?必須?持位運(yùn)算等匯編操作。位運(yùn)算就是對(duì)字節(jié)或字內(nèi)的?進(jìn)制數(shù)位進(jìn)?測(cè)試、抽取、設(shè)置或移位等操作
    2022-04-04
  • QT已有項(xiàng)目導(dǎo)入工程時(shí)注意事項(xiàng)圖文詳解

    QT已有項(xiàng)目導(dǎo)入工程時(shí)注意事項(xiàng)圖文詳解

    QT開(kāi)發(fā)這幾年大大小小項(xiàng)目做了不少,花了點(diǎn)時(shí)間對(duì)知識(shí)點(diǎn)總結(jié)整合了一部分,下面這篇文章主要給大家介紹了關(guān)于QT已有項(xiàng)目導(dǎo)入工程時(shí)注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 深入分析父子線程、進(jìn)程終止順序不同產(chǎn)生的結(jié)果

    深入分析父子線程、進(jìn)程終止順序不同產(chǎn)生的結(jié)果

    本篇文章是對(duì)父子線程、進(jìn)程終止順序不同產(chǎn)生的結(jié)果進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評(píng)論