EDIT:だから、私はまだ(私も、私は一度考えていたものを覚えて、それができない私の元の答えは悪いと誤解されていても、後でこの数ヶ月で票を得ている気づきました)私は、人々がまだ検索を通してここに来なければならないので、私は状況を明確にしようと思うと思った。最も通常の状況では
、あなたは
struct A { int i; };
int A_foo(A* this) { return this->i; };
A a; A_foo(&a);
として
struct A { int i; int foo() { return i; } };
A a; a.foo();
のかなりのシンクタンク(右、C
見えるように起動する?)ことができますので、あなただけのポインタ&A::foo
は、と思うだろう通常の関数ポインタと同じでなければなりません。しかし、いくつかの合併症があります:多重継承と仮想関数。
だから、我々が持っている想像:
struct A {int a;};
struct B {int b;};
struct C : A, B {int c;};
それはこのようにレイアウトされる可能性があります:あなたが見ることができるようにあなたがA*
かでオブジェクトを指すようにしたい場合は、
C*
の場合、開始点を指していますが、B*
を指す場合は、中央のどこかを指す必要があります。だからC
がB
からいくつかのメンバ関数を継承し、それを指し示したい場合は、C*
の関数を呼び出して、this
ポインタをシャッフルすることを知る必要があります。その情報はどこかに保存する必要があります。だから関数ポインタでまとめられます。
virtual
の関数を持つすべてのクラスについて、コンパイラはという仮想テーブルという名前のリストを作成します。その後、このテーブルへの余分なポインタをクラスに追加します(vptr)。したがって、このクラス構造のために:
struct A
{
int a;
virtual void foo(){};
};
struct B : A
{
int b;
virtual void foo(){};
virtual void bar(){};
};
コンパイラはこのようにそれを作るに終わるかもしれない:
ので、仮想関数へのメンバ関数ポインタは、実際には仮想テーブルへのインデックスである必要があります。 したがって、メンバー関数ポインタは、実際には1)関数ポインタ、2)場合によってはthis
ポインタの調整、3)場合によってはvtableインデックスが必要です。一貫性を持たせるためには、すべてのメンバ関数ポインタがこれらすべてのものに対応可能である必要があります。したがって、ポインタの場合は8
バイト、調整の場合は4
バイト、インデックスの場合は4
バイト、合計で16
バイトです。
これは実際にはコンパイラ間で多くのものが変わっていると思うし、可能な最適化がたくさんある。おそらく私が記述した方法で実際に実装する人はいません。
ロット詳細については、this(「メンバー関数ポインタの実装」までスクロール)を参照してください。
本質的に、標準では、データポインタ、関数ポインタ、およびメンバ関数ポインタのサイズがすべて同じである必要はありません。彼らがあなたのプラットフォームで同じサイズを持っていない理由を知りたければ、あなたのC++コンパイラの保守担当者に尋ねる必要があります。 http://www.parashift.com/c++-faq/cant-cvt-memfnptr-to-voidptr.html http://www.parashift.com/c++-faq/cant-cvt-fnptr-to-voidptr.html – Cubic
@KirilKirov問題ありません。私はいつも悪口ではない:) –