首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 虛函數與抽象基類:多態機制深度解析與實戰建模

     編輯:關於C語言

核心概念

  • 虛函數:基類聲明 virtual,派生類**覆寫**(同簽名)。通過基類指標/引用調用時發生**動態綁定**(運行期根據對象真實類型決定調用哪個版本)。
  • 純虛函數:virtual RetType func() = 0; 無實作,強制派生類實現。
  • 抽象基類:含至少一個純虛函數的類。**不可實例化**,只能作為介面規範與多態根節點。

經典建模:幾何形狀體系

類別層次


          Shape (抽象基類)
          /    |    \
       Point  Circle  Cylinder

完整代碼實現


#include <iostream>
#include <cmath>
using namespace std;

// 1. 抽象基類
class Shape {
public:
    virtual float area()    const { return 0.0f; }
    virtual float volume()  const { return 0.0f; }
    virtual void  shapeName() const = 0; // 純虛函數
    virtual ~Shape() = default;          // 虛解構函數!關鍵
};

// 2. Point:點(無面積、體積)
class Point : public Shape {
    float x_, y_;
public:
    Point(float x=0, float y=0) : x_(x), y_(y) {}
    void setPoint(float x, float y) { x_=x; y_=y; }
    float getX() const { return x_; }
    float getY() const { return y_; }
    void shapeName() const override { cout << "Point: "; }
    friend ostream& operator<<(ostream& os, const Point& p) {
        return os << '[' << p.x_ << ',' << p.y_ << ']';
    }
};

// 3. Circle:繼承 Point(圓心座標複用)
class Circle : public Point {
    float r_;
public:
    Circle(float x=0, float y=0, float r=0) : Point(x,y), r_(r) {}
    void setRadius(float r) { r_=r; }
    float getRadius() const { return r_; }
    float area() const override { return 3.14159f * r_ * r_; }
    void shapeName() const override { cout << "Circle: "; }
    friend ostream& operator<<(ostream& os, const Circle& c) {
        return os << static_cast(c) << ", r=" << c.r_;
    }
};

// 4. Cylinder:繼承 Circle(底面積複用)
class Cylinder : public Circle {
    float h_;
public:
    Cylinder(float x=0, float y=0, float r=0, float h=0) : Circle(x,y,r), h_(h) {}
    void setHeight(float h) { h_=h; }
    float area() const override {
        return 2*Circle::area() + 2*3.14159f*getRadius()*h_; // 全表面積
    }
    float volume() const override { return Circle::area() * h_; }
    void shapeName() const override { cout << "Cylinder: "; }
    friend ostream& operator<<(ostream& os, const Cylinder& cy) {
        return os << static_cast(cy) << ", h=" << cy.h_;
    }
};

// 5. 主程式演示靜態/動態綁定
int main() {
    Point pt(3.2f, 4.5f);
    Circle cir(2.4f, 1.2f, 5.6f);
    Cylinder cyl(3.5f, 6.4f, 5.2f, 10.5f);

    // 靜態綁定:對象類型確定,編譯期決定調用
    pt.shapeName();  cout << pt << endl;
    cir.shapeName(); cout << cir << endl;
    cyl.shapeName(); cout << cyl << endl << endl;

    // 動態綁定:基類指標指向不同派生對象
    Shape *sp;
    sp = &pt;  sp->shapeName();  cout << "x=" << pt.getX() << ",y=" << pt.getY()
         << "\narea=" << sp->area() << "\nvolume=" << sp->volume() << "\n\n";
    sp = ○ sp->shapeName();  cout << "x=" << cir.getX() << ",y=" << cir.getY()
         << "\narea=" << sp->area() << "\nvolume=" << sp->volume() << "\n\n";
    sp = &cyl; sp->shapeName();  cout << "x=" << cyl.getX() << ",y=" << cyl.getY()
         << "\narea=" << sp->area() << "\nvolume=" << sp->volume() << "\n\n";
    return 0;
}

運行結果解讀


Point: [3.2,4.5]
Circle: [2.4,1.2], r=5.6
Cylinder: [3.5,6.4], r=5.2, h=10.5

Point: x=3.2,y=4.5
area=0
volume=0

Circle: x=2.4,y=1.2
area=98.52
volume=0

Cylinder: x=3.5,y=6.4
area=512.60
volume=891.96

關鍵觀察:同一 Shape* 調用 area()/volume(),根據實際對象(Point/Circle/Cylinder)執行不同代碼 —— **多態**核心價值。

七大設計結論

  1. 抽象基類封裝**共性介面**(area, volume, shapeName),派生類實現**特有行為**。
  2. 虛解構函數 **強制要求**:刪除基類指標時確保派生類解構函數被調用,防止資源洩漏。
  3. 派生類覆寫函數**自動為虛函數**(無需重複 virtual),建議加 override (C++11) 讓編譯器檢查簽名一致。
  4. 靜態綁定(對象/引用直接調用)vs 動態綁定(基類指標/引用調用),前者效能高、後者靈活。
  5. 介面與實現分離:庫提供者發布抽象基類頭文件,用戶自行派生,無需知道內部實現細節。
  6. 多態將「做什麼」(介面)與「怎麼做」(實現)分離,應用層代碼簡化為 shape->area(),細節下沉到類庫。
  7. **組合優於繼承**:若無「is-a」關係(如 Circle 包含 Point 而非「是一個」Point),優先用組合;本例為教學演示繼承關係。

工程落地提示

  • 大型專案將抽象介面放入獨立 interfaces/ 目錄,實現類放入 impl/,通過工廠模式創建對象。
  • 效能敏感路徑(遊戲實體更新、高頻交易)可用 **CRTP (Curiously Recurring Template Pattern)** 實現靜態多態,消除虛函數表查找開銷。
  • 跨 DLL 邊界導出類時,確保虛函數表布局一致(同編譯器、同編譯選項),或改用純 C 介面 + 手工 vtable。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved