為了更直觀的感受到記憶體佈局,我們使用gcc的編譯選項-fdump-lang-class
檢視
如下程式碼
class Base{
public:
Base(){}
virtual ~Base(){}
privte:
int i;
};
使用如下命令編譯
g++ -O0 -std=c++11 -fdump-lang-class test.cpp
可以得到一個顯示記憶體佈局的檔案a-test.cpp.001l.class
Vtable for Base
Base::_ZTV4Base: 4 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base)
16 (int (*)(...))Base::~Base
24 (int (*)(...))Base::~Base
Class Base
size=16 align=8
base size=12 base align=8
Base (0x0x7eafaf550420) 0
vptr=((& Base::_ZTV4Base) + 16)
從Lippman的C++物件模型中我們知道,在含有虛擬函式的類中,編譯器都會生成一個指標,用來指向虛擬函式表
可知,類中包含一個整型變數i
和一個虛擬函式表指標vptr
,由於對齊,Base
佔用16個位元組
虛擬函式表中包含4個指標,每個大小為8位元組
第一個為offset
,儲存了虛擬函式表指標的偏移
第二個為typeinfo
,指向型別資訊物件,用於RTTI
第三個為complete object destructor
第四是deleting destructor
繼承下的物件模型
如下程式碼
class Base{
public:
Base(){}
virtual ~Base(){}
private:
int i;
};
class Derive:public Base{
public:
Derive(int i){}
virtual ~Derive(){}
virtual void get(){}
virtual void set(){}
private:
int j
};
class Single:public Derive{
public:
Single(int i){}
void set()override{}
virtual void print(){}
private:
int k;
};
得到檔案
Vtable for Base
Base::_ZTV4Base: 4 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base)
16 (int (*)(...))Base::~Base
24 (int (*)(...))Base::~Base
Class Base
size=16 align=8
base size=12 base align=8
Base (0x0x7a6689b50420) 0
vptr=((& Base::_ZTV4Base) + 16)
Vtable for Derive
Derive::_ZTV6Derive: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI6Derive)
16 (int (*)(...))Derive::~Derive
24 (int (*)(...))Derive::~Derive
32 (int (*)(...))Derive::get
40 (int (*)(...))Derive::set
Class Derive
size=16 align=8
base size=16 base align=8
Derive (0x0x7a6689a0e1a0) 0
vptr=((& Derive::_ZTV6Derive) + 16)
Base (0x0x7a6689b508a0) 0
primary-for Derive (0x0x7a6689a0e1a0)
Vtable for Single
Single::_ZTV6Single: 7 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI6Single)
16 (int (*)(...))Single::~Single
24 (int (*)(...))Single::~Single
32 (int (*)(...))Derive::get
40 (int (*)(...))Single::set
48 (int (*)(...))Single::print
Class Single
size=24 align=8
base size=20 base align=8
Single (0x0x7a6689a0e208) 0
vptr=((& Single::_ZTV6Single) + 16)
Derive (0x0x7a6689a0e270) 0
primary-for Single (0x0x7a6689a0e208)
Base (0x0x7a6689b50d80) 0
primary-for Derive (0x0x7a6689a0e270)
單繼承場景,派生類只有一個虛擬函式表,複製於基類,同時將override
的虛擬函式進行覆蓋,派生類的虛擬函式也追加到表尾
派生類新增的非靜態成員變數,也會追加到基類的成員變數後面
靜態成員變數儲存在.
段,為堆區
多繼承下的物件模型
非菱形繼承
class Base_A{
public:
Base_A(int i){}
virtual ~Base_A(){}
int get(){}
virtual void set(){}
static void countA(){}
private:
int i;
static int ii;
};
class Base_B{
public:
Base_B(int i){}
virtual ~Base_B(){}
int get(){}
virtual void set(){}
virtual void add(){}
static void countA(){}
private:
int j;
static int jj;
};
class Derive:public Base_A,public Base_B{
public:
Derive(int d){}
void add()override{}
void set()override{}
virtual void print(){}
private:
int k;
};
生成如下
Vtable for Base_A
Base_A::_ZTV6Base_A: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI6Base_A)
16 (int (*)(...))Base_A::~Base_A
24 (int (*)(...))Base_A::~Base_A
32 (int (*)(...))Base_A::set
Class Base_A
size=16 align=8
base size=12 base align=8
Base_A (0x0x7983aa950420) 0
vptr=((& Base_A::_ZTV6Base_A) + 16)
Vtable for Base_B
Base_B::_ZTV6Base_B: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI6Base_B)
16 (int (*)(...))Base_B::~Base_B
24 (int (*)(...))Base_B::~Base_B
32 (int (*)(...))Base_B::set
40 (int (*)(...))Base_B::add
Class Base_B
size=16 align=8
base size=12 base align=8
Base_B (0x0x7983aa9509c0) 0
vptr=((& Base_B::_ZTV6Base_B) + 16)
Vtable for Derive
Derive::_ZTV6Derive: 13 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI6Derive)
16 (int (*)(...))Derive::~Derive
24 (int (*)(...))Derive::~Derive
32 (int (*)(...))Derive::set
40 (int (*)(...))Derive::add
48 (int (*)(...))Derive::print
56 (int (*)(...))-16
64 (int (*)(...))(& _ZTI6Derive)
72 (int (*)(...))Derive::_ZThn16_N6DeriveD1Ev
80 (int (*)(...))Derive::_ZThn16_N6DeriveD0Ev
88 (int (*)(...))Derive::_ZThn16_N6Derive3setEv
96 (int (*)(...))Derive::_ZThn16_N6Derive3addEv
Class Derive
size=32 align=8
base size=32 base align=8
Derive (0x0x7983aa963930) 0
vptr=((& Derive::_ZTV6Derive) + 16)
Base_A (0x0x7983aa950f00) 0
primary-for Derive (0x0x7983aa963930)
Base_B (0x0x7983aa950f60) 16
vptr=((& Derive::_ZTV6Derive) + 72)
可以看出派生類中存在兩個虛擬函式表指標vptr
enable_shared_from_this特性
表現為讓例項擁有一個弱引用
如下程式碼
class Derive:public Base,
public std::enable_shared_from_this<Derive{
public:
Derive(int i){}
void set()override;
virtual void print();
private:
int i;
};
可以看出,記憶體有所增大,因為enable_shared_from_this
繼承多佔用了16位元組
從std::weak_ptr實現中可知,實際上儲存了兩個指標
enable_shared_from_this不影響Derive的虛擬函式表內容