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

C++ 虛繼承解析:解決菱形繼承中的資料冗餘與二義性

     編輯:關於C語言

前言

菱形繼承(`A ← B, C → D`)會導致派生類 `D` 包含兩份基類 `A` 的成員,造成記憶體浪費與名稱二義性。虛繼承(`virtual public`)通過共享單一基類子物件完美解決此問題。本文以 `Person → Teacher/Student → Graduate` 為例,完整演示虛繼承語法、記憶體佈局與構造順序。

代碼實現

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

// 間接基類
class Person {
protected:
    int age;
    char sex;
    string name;
public:
    Person(int a, char s, string n) : age(a), sex(s), name(n) {}
};

// 虛繼承:關鍵字 virtual
class Teacher : virtual public Person {
protected:
    string title;
public:
    Teacher(int a, char s, string n, string t) : Person(a, s, n), title(t) {}
};

class Student : virtual public Person {
protected:
    float score;
public:
    Student(int a, char s, string n, float sc) : Person(a, s, n), score(sc) {}
};

// 最終派生類:必須直接調用虛基類構造函數
class Graduate : public Teacher, public Student {
protected:
    float wage;
public:
    Graduate(int a, char s, string n, string t, float sc, float w)
        : Person(a, s, n),      // 必須顯式初始化虛基類
          Teacher(a, s, n, t),
          Student(a, s, n, sc),
          wage(w) {}
    void show() {
        cout << name << endl;
        cout << age << endl;
        cout << sex << endl;
        cout << title << endl;
        cout << score << endl;
        cout << wage << endl;
    }
};

int main() {
    Graduate gr(22, 'F', "Alice", "Professor", 89.5f, 79.5f);
    gr.show();
    return 0;
}

輸出結果

Alice
22
F
Professor
89.5
79.5

核心機制圖解

非虛繼承記憶體佈局 (菱形)          虛繼承記憶體佈局
┌─────────────┐                     ┌─────────────┐
│   Graduate  │                     │   Graduate  │
├─────┬───────┤                     ├─────┬───────┤
│Teacher      │                     │Teacher      │
│  └ Person   │                     │  └ (vptr)   │
├─────┼───────┤                     ├─────┼───────┤
│Student      │                     │Student      │
│  └ Person   │  ← 兩份 Person!      │  └ (vptr)   │
└─────────────┘                     └─────┬───────┘
                                          │  Person (共享單份)
                                          └─────────────┘

關鍵規則總結

  1. 聲明處加 `virtual`:`class B : virtual public A`,`class C : virtual public A`。
  2. 最遠派生類負責構造虛基類:`Graduate` 的初始化列表**必須**出現 `Person(...)`,否則編譯錯誤(若 `Person` 無預設構造函數)。
  3. 虛基類構造順序:按繼承圖深度優先、從左到右,**虛基類最先構造**,且僅構造一次。
  4. 訪問虛基類成員:直接用成員名,無二義性;編譯器透過 `vptr` + 偏移量間接訪問。
  5. 體積代價:每個虛繼承關係在對象中引入一個隱藏指標 (`vptr`),增加 4/8 字節。

常見誤區

  • ❌ 以為 `virtual` 在派生類 `Graduate` 宣告處加 → 應在**中間層** `Teacher`/`Student` 宣告處加。
  • ❌ 忘記在最遠派生類初始化列表寫虛基類構造 → 編譯報錯 "no matching constructor"。
  • ❌ 認為虛繼承會影響多態 → 虛繼承解決**資料共享**,虛函數解決**行為多態**,兩者正交。

實際應用場景

  • IO 流體系:`ios_base` → `istream`/`ostream` → `iostream`(標準庫即用虛繼承)。
  • 組件框架:多介面聚合時避免重複基礎設施子物件。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved