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

C++ 虛函數核心機制:從面試題到虛表佈局深度剖析

     編輯:關於C語言

一、經典面試題:輸出什麼?

class A { public: virtual void p() { cout << "A" << endl; } };
class B : public A { public: virtual void p() { cout << "B" << endl; } };
int main() {
    A* a = new A; A* b = new B;
    a->p(); b->p(); // 輸出:A  B
    delete a; delete b;
}

基類指針指向派生對象,調用虛函數 → 動態綁定,輸出 A B。

二、有無 virtual 的本質區別

1. 無 virtual(靜態綁定)

A* b = new B; b->p(); 編譯期確定調用 A::p(),輸出 A A。因非虛函數調用在編譯期靜態綁定,忽略對象實際類型。

2. 有 virtual(動態綁定)

關鍵認知:
a. 基類指針/引用調用虛函數時,直到運行時才知對象確切類型。
b. 非虛函數:無論實際類型,執行基類版本。
虛函數:運行時根據指針指向的對象類型,調用該類型定義的版本。
故 b->p() 調用 B::p(),輸出 A B。

三、虛函數底層實現:虛表與 vptr

通用模型:
• 每個含虛函數的類有一個虛表,存放虛函數地址。
• 每個對象含一個vptr,指向其類的虛表。

引用《深度探索 C++ 對象模型》經典例子

class Point {
public:
    virtual ~Point();
    virtual Point& mult(float) = 0; // 純虛
    float x() const { return _x; }  // 非虛,不進虛表
    virtual float y() const { return 0; }
    virtual float z() const { return 0; }
protected:
    Point(float x = 0.0); float _x;
};

class Point2d : public Point {
public:
    Point2d(float x=0, float y=0) : Point(x), _y(y) {}
    ~Point2d();                    // 覆寫
    Point2d& mult(float);          // 覆寫
    float y() const { return _y; } // 覆寫
protected:
    float _y;
};

class Point3d : public Point2d {
public:
    Point3d(float x=0, float y=0, float z=0) : Point2d(x,y), _z(z) {}
    ~Point3d(); 
    Point3d& mult(float);
    float z() const { return _z; }
protected:
    float _z;
};

虛表佈局(單繼承)

  1. Point 虛表:~Point(slot1), mult(slot2), y(slot3), z(slot4)。Point 對象含 _x + vptr。
  2. Point2d 虛表:覆寫 ~Point2d, mult, y;繼承 Point::z。對象含 _y + vptr(指向 Point2d 虛表)。
  3. Point3d 同理:覆寫 ~Point3d, mult, z;繼承 y。

虛表佈局圖:單繼承情況

總結

虛函數通過虛表 + vptr 實現運行時多態:構造時設置 vptr 指向正確虛表,調用時通過 vptr 定位槽位跳轉。單繼承下虛表按聲明順序線性佈局,派生類覆寫替換槽位,未覆寫繼承基類槽位。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved