1

クラス インスタンスとフィールドへのポインターが与えられると、このクラス インスタンスのフィールド変数を指す通常のポインターを取得できます。これは、次のコードの最後の代入と同様です。

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
}

この変換を逆にすることは可能ですか: コードのように、指定されたクラス インスタンスA a;int* r取得int A::* p(または、指定されたポインターが指定されたインスタンスにない場合は NULL ptr):

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
    int A::*s = // a--->r -how to extract r back to member pointer?
}

私が考えられる唯一の方法は、Aの既知のすべてのフィールドを取得し、特定のインスタンスのアドレスを計算し、特定のアドレスと比較する関数を作成することです。ただし、これにはクラスごとにカスタム コードを記述する必要があり、管理が難しくなる可能性があります。また、次善のパフォーマンスもあります。

このような変換は、私が知っているすべての実装の下でいくつかの操作でコンパイラーによって実行できると想像できます-そのようなポインターは通常、構造内のオフセットにすぎないため、特定のポインターが実際にこのクラスストレージにあるかどうかを確認するための減算と範囲チェックにすぎません. 仮想基本クラスは少し複雑になりますが、コンパイラが処理できないものは何もないと思います。ただし、標準で必要とされていないため(そうですか?)、コンパイラベンダーは気にしていないようです。

それとも私は間違っていますか?そのような変換には根本的な問題がありますか?

編集:

私が尋ねていることについて少し誤解があることがわかります。要するに、私は次のいずれかを尋ねています:

  • すでにいくつかの実装がありますが (つまり、コンパイラ レベルで)、ほとんど誰も使用していないため、ほとんど誰もそれについて知りません。
  • 標準では言及されておらず、コンパイラベンダーもそれについて考えていませんが、原則として実装することは可能です(繰り返しますが、コンパイルされたコードではなく、コンパイラによって)。
  • このような操作には、私が見逃した深刻な問題がいくつかあります。

私の質問は - それらのどれが本当ですか? そして最後の場合 - 根本的な問題は何ですか?

回避策を求めているわけではありません。

4

2 に答える 2

0

これを行うクロスプラットフォームの方法はありません。メンバー値へのポインターは、通常、オブジェクトの先頭へのオフセットとして実装されます。その事実を利用して、これを作成しました(VSで動作し、他に何も試していません):

class A
{
public:
    int i, j;
};

int main()
{
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;

    union
    {
        std::ptrdiff_t offset;
        int A::*s;
    };

    offset = r - reinterpret_cast<int*>(&a);
    a.*s = 7;
    std::cout << a.i << '\n';
}
于 2012-09-17T20:36:22.637 に答える
0

AFAIK C ++は完全なリフレクションを提供していません。これを行う必要があります。

1つの解決策は、自分で反射を提供することです(あなたが説明する方法は1つの方法であり、最良の方法ではないかもしれませんが、うまくいくでしょう).

完全に移植性のない解決策は、実行可能ファイルを見つけて、含まれている可能性のあるデバッグ情報を使用することです。明らかに移植性がなく、最初からデバッグ情報が必要です。

http://www.garret.ru/cppreflection/docs/reflect.htmlの導入セクションに、リフレクションの問題とそれに対するさまざまな可能なアプローチの適切な説明があります。

編集:

上で書いたように、移植可能で一般的な解決策はありません。しかし、非常に非移植的なアプローチがあるかもしれません。現時点ではテストするための C++ コンパイラがないため、ここでは実装を提供しませんが、アイデアについて説明します。

基本は、デイブが彼の答えで行ったことです。メンバーへのポインターはしばしば単なるオフセットであるという事実を利用します。問題は基本クラス (特に仮想および多重継承クラス) にあります。テンプレートを使用してアプローチできます。動的キャストを使用して、基本クラスへのポインターを取得できます。そして最終的に、そのポインターを元のポインターと比較して、ベースのオフセットを見つけます。

于 2012-09-17T20:34:21.360 に答える