C++虚関数メカニズム学習
25121 ワード
お礼を言う
本文はの読書とgdbの使用に基づいて完成した.ここでLippmanのcfront中の対象モデルに対する解析に感謝し、これらの解析は読者の霧を解くのに役立つ.また、Linuxの下でこの上なく強大なgdbツールは更に“暗い”の“明かり”を追い払うのです. :)
No-Inheritance
解析:
GDBを使用してメモリ領域を表示し、表示する
Baseにおけるaのアドレスは0 x 7 ffffffdc 50
Base中のcのアドレスは0 x 7 ffffffdc 54
Baseのbのアドレスは0 x 601068です
showBase 1のアドレスは0 x 40085 e(パラメータはBase*const->thisポインタは定数ポインタ)
showBase 2のアドレスは0 x 400888(パラメータはvoid)
明らかに
non-static data memberはclass objectに格納されます.
static data member,member functionは本classのすべてのオブジェクトがshareされているため、共通領域に配置されている.
Inheritance without Polymorphism
解析:
GDBを使用してメモリ領域を表示し、表示する
Inheriにおけるaのアドレスは0 x 7 fffffffdc 70
Inheri中のcのアドレスは0 x 7 fffffdc 78
Inheriのbのアドレスは0 x 601068です
Inheriにおけるbのアドレスは0 x 60106 c
showBase 1のアドレスは0 x 40085 e(パラメータはBase*const->thisポインタは定数ポインタ)
showInheri 1のアドレスは0 x 400888(パラメータはvoid)
明らかに
derived class objectには、ベースクラスと派生クラスのnon-static data memberが含まれています.
No-Inheritance with Polymorphism
gdbを使用してbase class object(p ptr)を表示する
" {_vptr.Base = 0x400af0, a = 21, static b = 10, c = 22} "
クラスでのダミーメカニズムの使用(ダミー関数、ダミーベースクラス、ダミー継承...この場合、objectごとにvptrが追加する、対応するvtblを指す.
gdbを使用してvptrが指す虚関数(p/a*(void**)0 x 400 af 0を表示
" {0x40092e, 0x697265686e4936} "
Single-Inheritance with Virtual Mechanism
Inheri class objectの表示
{ = {_vptr.Base = 0x400bc0 , a = 21, static b = 10, c = 22}, c = 23, static d = 11}
Ineri class objectのvtblの表示
0x400998
derived class objectはbase class subobjectから継承するvptrを直接使用していることがわかる.
同様に、Base class objectを表示
{_vptr.Base = 0x400be0, a = 21, static b = 10, c = 22}
Base class objectのvtblの表示
0x40096e
ここから、Single Inheritanceにおける各class objectのvtblには、本classに対応するvirtual functionのみが含むことがわかる.
derived classがbase class pointerに付与された場合をもう一度テストします.
Base* bbptr = new Inheri;
bbptrが指すメモリを表示するには、次の手順に従います.
{ = {_vptr.Base = 0x400bc0 , a = 21, static b = 10, c = 22}, c = 23, static d = 11}
vtblの内容を表示するには、次の手順に従います.
0x400998
ここでは2つの発見があります.
1)ベースクラスポインタBase*を使用してInheriオブジェクトを接続するが、vptrが指すvtblは依然としてInheri classである.
2)各classに対応するvtblはメモリに1部しかなく、bbprとiptrが指すvtblはテスト中に0 x 400 bc 0にある
Multiple-Inheritance with Virtual Mechanism
Finalオブジェクトの表示
"{ = {_vptr.OtherBase = 0x400cd0 , oa = 0}, = { = {_vptr.Base = 0x400ce8 , a = 21, static b = 10, c = 22}, c = 23, static d = 11}, }"
次のように表示されます.
1)サブオブジェクトの右から左へのコンストラクション
2)それぞれOtherBaseとBaseのvptrを含む、これはderived class objectがbase class objectに付与されたときに扱いやすいためである.
OtherBaseとBaseのvptrの情報の表示を続行
_vptr.OtherBaseが指すvtblの情報は、0 x 400 a 5 c
_vptr.Baseが指すvtblの情報は:0 x 400 a 86
この2つのvtblが保存されているのはすべてFinal::show.したがって、Finalによって各ベースクラスのポインタに値を付与場合、最後には常にFinal自身の虚関数が呼び出される.
Virtual Inheritance
virtual inheritanceを使用していない場合は、_を表示します.iostreamオブジェクト、2つのファイルが表示されます.iosクラスのオブジェクトは、それぞれ_に属します.istreamと_ostream :
"{<_istream> = {<_ios> = {_vptr._ios = 0x400c90, i = 0}, is = 0}, <_ostream> = {<_ios> = {
_vptr._ios = 0x400ca8, i = 0}, os = 0}, ios = 0}"
前に紹介したsingle inheritance with polymorphism,istreamと_ostreamはそれぞれ従_を使用しますiosから来たvptr.iosは自分のvtblを指します.
virtual inheritanceを使用すると、1部しか見えません.iosオブジェクト:
"{<_istream> = {<_ios> = {_vptr._ios = 0x400d18, i = 0}, _vptr._istream = 0x400cd8 , is = 0}, <_ostream> = {_vptr._ostream = 0x400cf8 , os = 0}, ios = 0}"
虚継承では,単一継承と同様にベースクラスを継承するvptrはなく,独自のvptrを持つ.
vtblの内容を引き続き表示し、それぞれを表示します.
0x400a40 <_ZTv0_n24_N9_iostream4showEv>
0x400a3a <_ZThn16_N9_iostream4showEv>
虚関数テーブルの関数もすべて_iostream classのmember function.したがって、iostreamオブジェクトがそのbase class subobjectに付与するポインタは、常に_に呼び出されます.iostream classのvirtual function.
Reference
コメント
詳細については、https://github.com/CarlSama/Inside-The-CPP-Object-Model-Reading-Notesを参照してください.
本文は
No-Inheritance
1 class Base {
2 public:
3 int a = 21;
4 static int b;
5 int c = 22;
6
7 void showBase1();
8 static int showBase2();
9 };
10
11 void Base::showBase1() {
12 cout<<"Base"<<endl;
13 }
14 int Base::showBase2() {
15 cout<<"base2"<<endl;
16 }
解析:
GDBを使用してメモリ領域を表示し、表示する
Baseにおけるaのアドレスは0 x 7 ffffffdc 50
Base中のcのアドレスは0 x 7 ffffffdc 54
Baseのbのアドレスは0 x 601068です
showBase 1のアドレスは0 x 40085 e(パラメータはBase*const->thisポインタは定数ポインタ)
showBase 2のアドレスは0 x 400888(パラメータはvoid)
明らかに
non-static data memberはclass objectに格納されます.
static data member,member functionは本classのすべてのオブジェクトがshareされているため、共通領域に配置されている.
Inheritance without Polymorphism
1 class Base {
2 public:
3 int a = 21;
4 static int b;
5 int c = 22;
6
7 void showBase1();
8 };
9 int Base::b = 10;
10 void Base::showBase1() {
11 cout<<"Base"<<endl;
12 }
13
14 class Inheri : public Base {
15 public:
16 int c = 23;
17 static int d;
18
19 static int showInheri1();
20 };
21 int Inheri::d = 11;
22 int Inheri::showInheri1(){
23 cout<<"Inheri"<<endl;
24 }
解析:
GDBを使用してメモリ領域を表示し、表示する
Inheriにおけるaのアドレスは0 x 7 fffffffdc 70
Inheri中のcのアドレスは0 x 7 fffffdc 78
Inheriのbのアドレスは0 x 601068です
Inheriにおけるbのアドレスは0 x 60106 c
showBase 1のアドレスは0 x 40085 e(パラメータはBase*const->thisポインタは定数ポインタ)
showInheri 1のアドレスは0 x 400888(パラメータはvoid)
明らかに
derived class objectには、ベースクラスと派生クラスのnon-static data memberが含まれています.
No-Inheritance with Polymorphism
1 class Base {
2 public:
3 int a = 21;
4 static int b;
5 int c = 22;
6
7 virtual void showBase1();//virtual function
8 };
9 int Base::b = 10;
10 void Base::showBase1() {
11 cout<<"Base"<<endl;
12 }
gdbを使用してbase class object(p ptr)を表示する
" {_vptr.Base = 0x400af0
クラスでのダミーメカニズムの使用(ダミー関数、ダミーベースクラス、ダミー継承...この場合、objectごとにvptrが追加する、対応するvtblを指す.
gdbを使用してvptrが指す虚関数(p/a*(void**)0 x 400 af 0を表示
" {0x40092e
Single-Inheritance with Virtual Mechanism
class Base {
public:
int a = 21;
static int b;
int c = 22;
virtual void showBase1();
};
int Base::b = 10;
void Base::showBase1() {
cout<<"Base"<<endl;
}
class Inheri : public Base {
public:
int c = 23;
static int d;
static int showInheri1();
};
int Inheri::d = 11;
int Inheri::showInheri1(){
cout<<"Inheri"<<endl;
}
Inheri class objectの表示
{
Ineri class objectのvtblの表示
0x400998
derived class objectはbase class subobjectから継承するvptrを直接使用していることがわかる.
同様に、Base class objectを表示
{_vptr.Base = 0x400be0
Base class objectのvtblの表示
0x40096e
ここから、Single Inheritanceにおける各class objectのvtblには、本classに対応するvirtual functionのみが含むことがわかる.
derived classがbase class pointerに付与された場合をもう一度テストします.
Base* bbptr = new Inheri;
bbptrが指すメモリを表示するには、次の手順に従います.
{
vtblの内容を表示するには、次の手順に従います.
0x400998
ここでは2つの発見があります.
1)ベースクラスポインタBase*を使用してInheriオブジェクトを接続するが、vptrが指すvtblは依然としてInheri classである.
2)各classに対応するvtblはメモリに1部しかなく、bbprとiptrが指すvtblはテスト中に0 x 400 bc 0にある
Multiple-Inheritance with Virtual Mechanism
1 class Base {
2 public:
3 int a = 21;
4 static int b;
5 int c = 22;
6
7 virtual void show();//inline
8 };
9 int Base::b = 10;
10 void Base::show() {
11 cout<<"Base"<<endl;
12 }
13
14 class Inheri : public Base {
15 public:
16 int c = 23;
17 static int d;
18
19 virtual void show();
20 };
21 int Inheri::d = 11;
22 void Inheri::show(){
23 cout<<"Inheri"<<endl;
24 }
25
26 class OtherBase{
27 public:
28 int oa;
29 virtual void show();
30 };
31 void OtherBase::show(){
32 cout<<"OtherBase"<<endl;
33 }
34
35 class Final : public OtherBase,public Inheri{
36 public:
37 virtual void show();
38 };
39 void Final::show() {
40 cout<<"Final"<<endl;
41 }
Finalオブジェクトの表示
"{
次のように表示されます.
1)サブオブジェクトの右から左へのコンストラクション
2)それぞれOtherBaseとBaseのvptrを含む、これはderived class objectがbase class objectに付与されたときに扱いやすいためである.
OtherBaseとBaseのvptrの情報の表示を続行
_vptr.OtherBaseが指すvtblの情報は、0 x 400 a 5 c
_vptr.Baseが指すvtblの情報は:0 x 400 a 86
この2つのvtblが保存されているのはすべてFinal::show.したがって、Finalによって各ベースクラスのポインタに値を付与場合、最後には常にFinal自身の虚関数が呼び出される.
Virtual Inheritance
1 class _ios {
2 public:
3 int i;
4 virtual void show();
5 };
6 void _ios::show() {
7 cout<<"ios"<<endl;
8 }
9
10
11 class _istream : public _ios {
12 public:
13 int is;
14 virtual void show();
15 };
16 void _istream::show() {
17 cout<<"istream"<<endl;
18 }
19
20 class _ostream : public _ios {
21 public:
22 int os;
23 virtual void show();
24 };
25 void _ostream::show() {
26 cout<<"ostream"<<endl;
27 }
28
29 class _iostream : public _istream, public _ostream {
30 public:
31 int ios;
32 virtual void show();
33 };
34 void _iostream::show() {
35 cout<<"iostream"<<endl;
36 }
virtual inheritanceを使用していない場合は、_を表示します.iostreamオブジェクト、2つのファイルが表示されます.iosクラスのオブジェクトは、それぞれ_に属します.istreamと_ostream :
"{<_istream> = {<_ios> = {_vptr._ios = 0x400c90
_vptr._ios = 0x400ca8
前に紹介したsingle inheritance with polymorphism,istreamと_ostreamはそれぞれ従_を使用しますiosから来たvptr.iosは自分のvtblを指します.
virtual inheritanceを使用すると、1部しか見えません.iosオブジェクト:
"{<_istream> = {<_ios> = {_vptr._ios = 0x400d18
虚継承では,単一継承と同様にベースクラスを継承するvptrはなく,独自のvptrを持つ.
vtblの内容を引き続き表示し、それぞれを表示します.
0x400a40 <_ZTv0_n24_N9_iostream4showEv>
0x400a3a <_ZThn16_N9_iostream4showEv>
虚関数テーブルの関数もすべて_iostream classのmember function.したがって、iostreamオブジェクトがそのbase class subobjectに付与するポインタは、常に_に呼び出されます.iostream classのvirtual function.
Reference
コメント
詳細については、https://github.com/CarlSama/Inside-The-CPP-Object-Model-Reading-Notesを参照してください.