13

メンバー関数からいくつかのコールバックを作成しようとしていますが、次のエラーが発生したときに2つのクラスから派生したテンプレートクラスをコールバックオブジェクトとして使用しようとするまで、すべて問題ありませんでした。

error C2440: 'reinterpret_cast' : Pointers to members have different representations; cannot cast between them

このことは、メンバー関数ポインターが異なる表現を持っていることを私に知らせました(doh!)

これらの表現は何ですか?それらの違いは何ですか?

4

2 に答える 2

22

ダニー・カレブはこれを非常にうまく説明しています:

メンバーへのポインタの基本的な表現

メンバーへのポインターは通常のポインターのように動作しますが、舞台裏ではそれらの表現はまったく異なります。実際、メンバーへのポインターは通常、特定の場合に最大4つのフィールドを含む構造体で構成されます。これは、メンバーへのポインタが、通常のメンバー関数だけでなく、仮想メンバー関数、複数の基本クラスを持つオブジェクトのメンバー関数、および仮想基本クラスのメンバー関数もサポートする必要があるためです。したがって、最も単純なメンバー関数は、2つのポインターのセットとして表すことができます。1つはメンバー関数の物理メモリアドレスを保持し、もう1つはthisポインタ。ただし、仮想メンバー関数、多重継承、仮想継承などの場合、メンバーへのポインターは追加情報を格納する必要があります。したがって、メンバーへのポインターを通常のポインターにキャストすることも、異なるタイプのメンバーへのポインター間で安全にキャストすることもできません。

コンパイラがメンバーへのポインタをどのように表すかを理解するには、sizeof演算子を使用します。次の例では、データメンバーへのポインターとメンバー関数へのポインターのサイズが取得されます。ご覧のとおり、サイズが異なるため、表現も異なります。

struct A
{
 int x;
 void f();
};
int A::*pmi = &A::x;
void (A::*pmf)() = &A::f;
int n = sizeof (pmi); // 8 byte with my compiler
int m = sizeof (pmf); // 12 bytes with my compiler

問題のクラスおよびメンバー関数が仮想であるかどうかに応じて、これらの各ポインターの表現が異なる場合があることに注意してください。

于 2012-12-14T09:27:55.963 に答える
4

これはMicrosoftのことです。これまで見てきたように、異なる表現を持つメンバー関数へのポインターを生成するという犠牲を払って、メンバー関数へのポインターを小さくする場合があります。これをオフにするスイッチ(/vmg)があり、メンバーへのすべてのポインターが同じ表現を持つようになっています。

于 2012-12-14T15:18:29.453 に答える