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

C++ 多重繼承解析:同名函數調用與對象大小計算

     編輯:關於C++

代碼示例

#include 
using namespace std;

class AA {
public:
    int a;
    void sayHello() { cout << "this is AA" << endl; }
};

class BB {
public:
    int b;
    void sayHello() { cout << "this is BB" << endl; }
};

class CC : public AA, public BB {
public:
    int d;
    void sayHello() { cout << "this is CC" << endl; }
};

int main() {
    CC cc;
    cc.sayHello();         // 調用 CC::sayHello()
    cc.AA::sayHello();     // 顯式調用 AA::sayHello()
    cc.BB::sayHello();     // 顯式調用 BB::sayHello()
    cc.CC::sayHello();     // 顯式調用 CC::sayHello()
    
    cout << "Size AA: " << sizeof(AA) << endl;  // 4
    cout << "Size BB: " << sizeof(BB) << endl;  // 4
    cout << "Size CC: " << sizeof(CC) << endl;  // 12
    return 0;
}

運行結果

this is CC
this is AA
this is BB
this is CC
Size AA: 4
Size BB: 4
Size CC: 12

關鍵分析

1. 同名函數調用規則

  • cc.sayHello() → 派生類版本(遮蔽基類)
  • cc.AA::sayHello() → 基類 AA 版本(作用域解析)
  • cc.BB::sayHello() → 基類 BB 版本
  • 若派生類未定義 sayHello,直接調用 cc.sayHello() 會報錯「二義性」

2. 對象大小計算

AA: int a (4)                    → 4
BB: int b (4)                    → 4
CC: AA(4) + BB(4) + int d(4)     → 12
  • 多重繼承對象包含所有基類子對象,按繼承聲明順序排列
  • 無虛繼承時,大小 = 所有基類大小之和 + 派生類自身成員大小(含對齊填充)
  • 有虛函數時,每個帶虛函數的基類子對象包含 vptr(+4/8 字節)

3. 內存佈局

CC 對象 (12 字節):
+--------+--------+--------+
| AA::a  | BB::b  | CC::d  |
| (4B)   | (4B)   | (4B)   |
+--------+--------+--------+
  偏移 0   偏移 4   偏移 8

4. 指針轉換與偏移

  • CC* → AA*:偏移 0(第一基類)
  • CC* → BB*:偏移 +4(第二基類)
  • 此偏移在 static_cast/dynamic_cast 中自動處理,void* 強轉會丟失(見文章 2610)

菱形繼承與虛繼承補充

class Base { int x; };
class A : virtual public Base { int a; };
class B : virtual public Base { int b; };
class C : public A, public B { int c; };

  • 虛繼承確保只有一份 Base 子對象
  • 引入 vbptr(虛基類表指針),對象大小增加
  • sizeof(C) 通常 > 非虛繼承版本

最佳實踐建議

  1. 避免多重繼承:優先使用組合(has-a)或介面繼承(單繼承純虛類)
  2. 必須多重繼承時:
    • 基類設計為「介面類」(純虛函數,無數據成員)
    • 避免同名非虛函數
    • 使用虛繼承解決菱形問題
  3. 指針轉換:始終用 static_cast/dynamic_cast,禁止 void* 中轉

總結

C++ 多重繼承將所有基類子對象按順序拼裝,對象大小為各部分之和。同名函數在派生類中會遮蔽基類版本,需通過作用域解析符顯式調用。理解內存佈局與指針偏移是正確使用多重繼承的前提,現代 C++ 開發建議盡量用組合替代。

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