この記事を読んでいる「仮想メソッド表」
上記の記事の例:
class B1 {
public:
void f0() {}
virtual void f1() {}
int int_in_b1;
};
class B2 {
public:
virtual void f2() {}
int int_in_b2;
};
class D : public B1, public B2 {
public:
void d() {}
void f2() {} // override B2::f2()
int int_in_d;
};
B2 *b2 = new B2();
D *d = new D();
この記事では、著者は、オブジェクトのメモリ レイアウトが次のd
ようになっていることを紹介しています。
d:
D* d--> +0: pointer to virtual method table of D (for B1)
+4: value of int_in_b1
B2* b2--> +8: pointer to virtual method table of D (for B2)
+12: value of int_in_b2
+16: value of int_in_d
Total size: 20 Bytes.
virtual method table of D (for B1):
+0: B1::f1() // B1::f1() is not overridden
virtual method table of D (for B2):
+0: D::f2() // B2::f2() is overridden by D::f2()
についての質問ですd->f2()
。への呼び出しはポインターをポインターとしてd->f2()
渡すため、次のようにする必要があります。B2
this
(*(*(d[+8]/*pointer to virtual method table of D (for B2)*/)[0]))(d+8) /* Call d->f2() */
元のポインターではなく、B2
ポインターをポインターとして渡す必要があるのはなぜですか??? 実際に D::f2() を呼び出しています。私の理解に基づいて、D::f2() 関数としてポインターを渡す必要があります。this
D
D
this
___アップデート____
B2
D::f2() にポインタを渡す場合、this
D::f2() 内のクラスのメンバにアクセスしたい場合はB1
?? ポインタB2
(これ)は次のように表示されると思います:
d:
D* d--> +0: pointer to virtual method table of D (for B1)
+4: value of int_in_b1
B2* b2--> +8: pointer to virtual method table of D (for B2)
+12: value of int_in_b2
+16: value of int_in_d
この連続したメモリ レイアウトの開始アドレスには、既に特定のオフセットがあります。たとえば、b1
D::f2() 内にアクセスしたい場合、実行時に次のようになると思います: *(this+4)
( this
b2 と同じアドレスを指す)b2
はB
????を指します。