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

C++ 動態綁定詳解:虛函數、指針/引用調用與對象切片陷阱

     編輯:C++ 入門

核心概念

C++ 動態綁定(多態)通過 虛函數 實現,但 必須通過指針或引用調用 才能觸發。直接用對象調用會發生「對象切片」,退化為靜態綁定。

代碼對比演示

✅ 正確:指針調用觸發動態綁定

#include <iostream>
using namespace std;

const double pi = 3.14;

class A {
public:
    A() {}
    virtual double area() const { return 0.0; }
};

class B : public A {
public:
    B(double r) : R(r) {}
    virtual double area() const { return pi * R * R; }
private:
    double R;
};

int main() {
    A* fig;
    B c(3.0);
    cout << "Area of B is ";
    fig = &c;           // 基類指針指向派生對象
    cout << fig->area() << endl;  // 動態綁定:調用 B::area()
    return 0;
}
// 輸出:Area of B is 28.26

❌ 錯誤:對象賦值導致切片,靜態綁定

int main() {
    A fig;              // 基類對象
    B c(3.0);
    cout << "Area of B is ";
    fig = c;            // 對象切片!只複製 A 部分
    cout << fig.area() << endl;  // 靜態綁定:調用 A::area()
    return 0;
}
// 輸出:Area of B is 0

深度解析:為什麼會切片?

調用方式靜態類型動態類型綁定類型結果
A* p = &b; p->f()A*B*動態B::f()
A& r = b; r.f()A&B動態B::f()
A a = b; a.f()AA靜態A::f()
b.f()BB靜態(但也是動態)B::f()

對象切片本質:A a = b; 僅拷貝 b 中繼承自 A 的成員(vptr 指向 A 的虛表),B 獨有成員(如 R)丟失,vptr 不變,故調用 A::area()。

虛函數表機制圖解

A 對象內存佈局:        B 對象內存佈局:
+----------+           +----------+
| vptr ──────────→  A's vtable   | vptr ──────────→  B's vtable
+----------+           +----------+
                       | R (double) |
                       +----------+

A's vtable:             B's vtable:
[0] &A::area()          [0] &B::area()

最佳實踐總結

  1. 基類析構函數必須虛化:防止 delete base_ptr 僅調用基類析構
  2. 多態調用只用指針/引用:值傳遞/返回會切片
  3. override 關鍵字 (C++11):編譯期檢查簽名匹配,防止隱藏而非覆蓋
  4. final 關鍵字 (C++11):禁止進一步覆蓋或繼承
  5. 純虛函數:virtual void f() = 0; 定義接口,強制派生類實現

進階陷阱:構造/析構中調用虛函數

class Base {
public:
    Base() { init(); }  // 危險!
    virtual void init() { cout << "Base init\n"; }
};
class Derived : public Base {
public:
    Derived() { /* ... */ }
    void init() override { cout << "Derived init\n"; }  // 不會被調用!
};

規則:構造函數中動態類型尚未完全形成,虛函數調用解析為當前構造層級的版本。析構函數同理(派生部分已銷毀)。

理解動態綁定機制與對象切片是 C++ 面向對象編程的分水嶺,也是面試高頻考點。

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