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

深度解析C++多重繼承與虛繼承的對象內存佈局複雜性

     編輯:關於C語言

前言

2012年春節深夜,鞭炮聲中研讀《Inside C++ Object Model》(侯捷譯),對C++對象佈局的精妙設計驚嘆不已。書中修正了原版諸多錯誤,不愧為經典。記得《Effective C++》條款7提到:「只有類含虛函數時才聲明虛析構函數」,當時僅知虛函數表存在,如今窺見全貌,方知其深意。—— Stay hungry, stay foolish!

單一繼承的對象佈局

無虛函數時類似C struct;有虛函數則引入vptr指向虛函數表。單一繼承下,派生類並非單純複製基類成員,而是以基類子對象形式佈局,遵循內存對齊原則。例如:

class BaseClass { protected: int m_nValue; char m_chValue; };
class DerivedClass1 : public BaseClass { protected: char m_chValue1; };
class DerivedClass2 : public DerivedClass1 { 
    // virtual void VFunction(){} 
    protected: char m_chValue2; 
};

VS2008下 sizeof(DerivedClass2) == 16。此佈局等價於包含委托對象:

class DerivedClass2 {
    // virtual void VFunction(){}
    protected: DerivedClass1 derived1; char m_chValue2;
};

虛繼承與多重繼承的佈局爆炸

基礎實驗

class BaseClass {};
class DerivedClassA : virtual public BaseClass { 
    public: /*virtual void VFunction(){}*/ 
};
class DerivedClassB : virtual public BaseClass {};
class DerivedClass : public DerivedClassA, public DerivedClassB {};

VS2008結果:

size of BaseClass        : 1  // 空類佔1字節確保地址唯一
size of DerivedClassA    : 4  // 含vbptr指向虛基類表
size of DerivedClassB    : 4  // 含vbptr
size of DerivedClass     : 8  // 兩個vbptr(VS未優化合併)

G++優化合併同類型vbptr,結果為1,4,4,4。

添加虛函數的影響

  • DerivedClassA加虛函數 → 增加vfptr,大小變8;DerivedClass變12。
  • 虛函數上移至BaseClass → 基類變4(含vfptr),兩派生類各增一個繼承來的vfptr變8,最派生類12(而非預期16,編譯器合併了同類型指針)。

核心結構解析

指針類型指向觸發條件
vfptr虛函數表(虛函數地址)類聲明虛函數
vbptr虛基類表(虛基類子對象地址)虛繼承基類

兩者初始化/析構均視為普通非靜態數據成員處理。

後記:回歸工程本質

Scott Meyers警告濫用虛函數會無形增加內存開銷。Lippman對對象模型的微觀剖析,讓我意識到:理解佈局不是為了炫技,而是為了在資源受限、性能敏感的系統中做精準決策。寫博客記錄,是為了不忘初心,更為下次踩坑時能秒懂。


本文出自「酋長」博客,轉載請保留出處。

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