2011-07-29 17 views
7

クラスのフィールドを指すポインタークラスのメンバーがあるとします。クラスの特定のインスタンスにその特定のフィールドへのポインタもあります。ポインターからメンバーへの親の復帰

class A { 
    B inner_object; 
} 

A* myA = /* ... */ 
B* ptr = &myA->inner_object; 
B A::* memPtr = &A::inner_object; 

myAを回復するためにptrmemPtrを使用する方法があります:たとえば、私たちはこのようなものを持っているのでしょうか?つまり、myAの明示的なポインタがまだない場合、ptrmemPtrのうち1つを作成できますか?

+0

もっと明確になるでしょうか。私はあなたがしたいことを理解していません。ごめんなさい。 – Mahesh

答えて

4

...

これは実際にはほとんどの産業侵入リストの実装で行われます。しかし、いくつかのハッカーを必要とします。侵入構造は、以下を使用します(はい、それは実装固有のもの)

ブースト

template<class Parent, class Member> 
inline const Parent *parent_from_member(const Member *member, const Member Parent::* ptr_to_member) 
{ 
    return (const Parent*)((const char*)member - 
     offset_from_pointer_to_member(ptr_to_member)); 
} 


template<class Parent, class Member> 
inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) 
{ 
    //The implementation of a pointer to member is compiler dependent. 
    #if defined(BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER) 
    //msvc compliant compilers use their the first 32 bits as offset (even in 64 bit mode) 
    return *(const boost::int32_t*)(void*)&ptr_to_member; 
    //This works with gcc, msvc, ac++, ibmcpp 
    #elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || \ 
    defined(__IBMCPP__) || defined(__DECCXX) 
    const Parent * const parent = 0; 
    const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member)); 
    return std::ptrdiff_t(member - reinterpret_cast<const char*>(parent)); 
    #else 
    //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC 
    return (*(const std::ptrdiff_t*)(void*)&ptr_to_member) - 1; 
    #endif 
} 

(Cではあるが)基本的に同じことcontainer_ofで、侵入リストを管理するために、Linuxカーネルに行われているように(ただし、ptr-to-membersは使用されません)。

#define container_of(ptr, type, member) ({ \ 
      const typeof(((type *)0)->member) *__mptr = (ptr); 
      (type *)((char *)__mptr - offsetof(type,member));}) 
3

あなたはしていません。メンバへのポインタは、それがメンバであるクラスのインスタンスを知らない。そのため、いつでものポインタを介してアクセスしたい場合は、インスタンスが必要です。

ポインタへのポインタは、ではなく、ポインタです。確かに、それをポインタと呼ぶのはおそらくC++委員会のミスであった。多くの(ほとんどではないが)実装では、ポインタのサイズさえも、ポインタへのポインタのサイズと同じではない。あなたがここで遊ぶことができるオフセットのトリックはありません。方法を見つけたとしても、ポインタへのポインタでデータを解析すると、その実装に固有のものになります。

+1

暗黙の質問は次のようなものだと思います。オブジェクトからオブジェクトへのポインタを得るためにもう一方を引く? –

+0

しかし、ptr-to-memberを単にオフセットと考えると、親は自明に回復可能でなければなりません。 ptr-to-memberがオフセットではない、あるいは同じように動作させることができないと言っていますか? (編集:oliが言ったこと) – bcr

+1

@Oli - 人々に狂ったアイデアを与える理由:-) – littleadv

1

できません。

メンバへのポインタは、特定のインスタンスに関する情報を格納しません。

型と、その型内の関数へのポインタのみを認識します。

1

これは間違いなく、標準ではないと、本当に実際の使用はお勧めできませんが、あなたはこれを試すことができます。

A *fake_A= reinterpret_cast<A *>(1); 
B *fake_B= &(fake_A->*ptr_to_member); 
char *fake_A_raw= static_cast<char *>(static_cast<void *>(fake_A)); 
char *fake_B_raw= static_cast<char *>(static_cast<void *>(fake_B)); 

ptrdiff_t offset_to_A_from_B= fake_B - fake_A; 

char *member_raw= static_cast<char *>(static_cast<void *>(member)); 
char *base_raw= member_raw - offset_to_A_from_B; 
A *base= static_cast<A *>(static_cast<void *>(base_raw)); 

そして、あなたは本当にこれを行うべきではありません。研究のまともな量の後

+0

と、なぜこれを投稿していますか? :P – YeenFei

+0

母親はい、それはかなり素晴らしい例です。しかし、私たちが利用できるものと本質的に同じことをする簡単な方法はおそらくありますか?たとえば、タイプAの構造体へのポインタがある場合は、ポインタから構造体へのポインタを減算してオフセットを得ることができます。または私は何かを逃していますか? – bcr

+0

@bcr、それはあなたが求めているものではありません。あなたは、メンバーへのポインタを与えられてルートクラスに戻る方法を知りたがっていました。メンバへのポインタをオフセットに直接キャストすることはできません。たとえば、メンバへのnullポインタはビット単位でゼロである必要はありません。 – MSN

0

これは可能であり、非常に便利です。メンバへのポインタが格納されている構造体の型がわかっている限り、メンバへのポインタはオフセットにすぎません。

関連する問題