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

C++ 對象內存佈局深度解析:單繼承、多重繼承、虛繼承下的 vptr 與 vtable

     編輯:C++ 入門

環境:Ubuntu 12.04 + GCC 4.8.1。本文通過實測內存佈局,揭示虛函數表指針 (vptr) 與虛函數表 (vtable) 在三種繼承模式下的組織規律。

一、單繼承

class Base { virtual void f(); virtual void g(); int bval; };
class Derived : public Base { virtual void f(); virtual void h(); int dval; }

佈局:

  • 對象首部:vptr → 指向 Derived 的 vtable;
  • 緊接:Base::bval、Derived::dval(按聲明順序);
  • vtable:Derived::f、Base::g、Derived::h、nullptr(GCC 特有尾部哨兵);
  • 覆寫函數原地替換,不增加槽位。

二、多重繼承

class Base1 { virtual void f(); virtual void g(); int b1; };
class Base2 { virtual void f(); virtual void g(); int b2; };
class Derived : public Base1, public Base2 { virtual void f(); virtual void h(); int d; }

佈局:

  • 依次包含 Base1 子對象(含 vptr1)、Base2 子對象(含 vptr2)、Derived 自身成員;
  • vtable1:Derived::f、Base1::g、Derived::h、哨兵;
  • vtable2:Derived::f、Base2::g、哨兵;
  • 同名虛函數 f 在兩個 vtable 中均被覆寫;
  • 若未覆寫同名函數,調用時需顯式指定 Base1::f() 否則二義性。

三、虛繼承(菱形)

class Base { virtual void f(); virtual void t(); int b; };
class Base1 : virtual public Base { virtual void f(); virtual void g(); virtual void k(); int b1; };
class Base2 : virtual public Base { virtual void f(); virtual void g(); virtual void k(); int b2; };
class Derived : public Base1, public Base2 { virtual void f(); virtual void g(); virtual void h(); int d; }

佈局:

  • 先非虛基類(按聲明順序):Base1 子對象(含 vptr)、Base2 子對象(含 vptr);
  • 再派生類自身成員:d;
  • 最後虛基類 Base 子對象(含 vptr),全程只有一份;
  • vtable1(Base1 的):Derived::f、Derived::g、Base1::k、Derived::h、哨兵;
  • vtable2(Base2 的):Derived::f、Derived::g、Base2::k、哨兵;
  • vtable3(Base 的):Derived::f、Base::t、哨兵。

關鍵總結

特性單繼承多重繼承虛繼承
vptr 數量1每個直接基類 1 個每個直接非虛基類 1 個 + 虛基類 1 個
基類份數1每個直接基類 1 份虛基類僅 1 份
虛函數表組織單表,覆寫原地替換每基類一表,派生虛函數放首表非虛基類各自表,虛基類單獨表
派生虛函數位置首表首表首個非虛基類表

理解佈局有助於調試多態調用、分析對象大小、解決切片問題、編寫序列化/反射工具。

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