2

アプリケーションに次のようなコードがあります。

class A
{
  public: int b;
}

class C
{
  public: int d;
}

void DoThings (void *arg1, MYSTERYTYPE arg2);

A obj_a;
C obj_c;

DoThings(&obj_a, &A::b);
DoThings(&obj_c, &C::d);

問題は - MYSTERYTYPE はどうあるべきか? void* も int も機能しませんが、値 &A::b は、printf を介して出力すると問題なく出力されます。

明確化: はい、&A::b は C++ で定義されています。はい、クラス メンバーへのオフセットを取得しようとしています。はい、私はトリッキーです。

編集: ああ、offsetof() を使用できます。とにかくありがとう。

4

4 に答える 4

6

2つの無関係なクラスへのデータメンバーポインタがあります。さて、両方のポインタを保持できる共通の型を見つけることはできません。これは、関数パラメーターが派生のメンバーへのデータメンバーポインターである場合にのみ機能します。これは、ベースにメンバーが含まれている場合、メンバーも含まれることが保証されているためです。

struct a { int c; }; struct b : a { }; int main() { int b::*d = &a::c; }

更新:上記が暗黙的にからa::*に変換される理由を書く必要があると思います。b::*結局のところ、私たちは通常しなければb*なりませa*ん!検討:

struct a { };
struct b : a { int c; };
struct e : a { };
int main() { int a::*d = &b::c; e e_; (e_.*d) = 10; /* oops! */ }

上記が有効であるならば、あなたは本当に多くの失敗をするでしょう。からへの変換は暗黙的ではないため、上記は無効です。ご覧のとおり、b :: cへのポインターを割り当てた後、それをまったく含まないクラスを使用して、ポインターを逆参照することができます。()。コンパイラーはこの順序を強制します:b::*a::*e

int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }

メンバーポインタポインタが属するクラスから派生していないため、コンパイルに失敗します。良い!ただし、以下は非常に有効であり、もちろんコンパイルされます(変更されたクラスと):ebab

struct a { int c; };
struct b : a { };
struct e : a { };
int main() { int e::*d = &a::c; e e_; (e_.*d) = 10; /* works! */ }

ケースで機能させるには、関数をテンプレートにする必要があります。

template<typename Class>
void DoThings (int Class::*arg) { /* do something with arg... */ }

これで、コンパイラは、指定されたメンバーポインタも属する正しいクラスを自動推測します。実際にインスタンスを使用するには、メンバーポインタと一緒にインスタンスを渡す必要があります。

template<typename Class>
void DoThings (Class & t, int Class::*arg) { 
    /* do something with arg... */ 
    (t.*arg) = 10;
}

DoThingsを作成するときにすでに知っているメンバーを設定したいだけの場合は、次のようにすれば十分です。

template<typename Class>
void DoThings (Class & t) {  
    t.c = 10;
}
于 2009-01-07T15:48:19.480 に答える
2

AまたはCオブジェクト内にたまたま存在する整数のアドレスで関数を呼び出そうとしているだけですか? その場合、Jeff McGlynn の回答が最適です。

それ以外の場合は、C++ の奇妙なメンバーへのポインター機能を必要とするトリッキーなことを実際に実行しようとしている場合 (ほとんどの場合そうではありません):

クラスACは無関係であるため、両方を処理するにはテンプレート関数が必要です。

template <typename T>
void DoThings(int T::*x);

Cが実際に から派生した場合A、次のようになります。

void DoThings(int A::*x);
于 2009-01-07T15:44:52.467 に答える
0

&A::b と &C::d は無意味です。関連付けられたアドレスはありません。メンバーのオフセットを取得しようとしていますか?

次のようなものは本当に必要ありませんか?

DoSomething(&obj_a,&obj_a.b);
于 2009-01-07T16:22:18.757 に答える
0

j_random_hacker が提案するようにテンプレートを使用し、関数を呼び出す時点でコンパイラが各クラスの型を認識している場合、質問に対する文字通りの答えは " template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER)" です。

あなたの例にどのように適合するかは次のとおりです。

#include <iostream>

class A {
public: 
    int b;
};

class C {
public: 
    int d;
};

template <typename CLASS>
void DoThings (CLASS * object, int CLASS::*MEMBER)
{
    std::cout << object->*MEMBER << std::endl;
}

A obj_a = { 2 };
C obj_c = { 4 };

int main (int argc, const char * argv[])
{
    DoThings(&obj_a, &A::b);
    DoThings(&obj_c, &C::d);
    return 0;
}
于 2011-05-05T14:47:45.107 に答える