7

假设我们有一个指向类成员的指针,指向类的一个字段。在类的特定实例中,我们还有一个指向该特定字段的指针。例如,我们可能有这样的事情:

class A {
     B inner_object;
}

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

有没有办法使用ptrmemPtr恢复myA?也就是说,如果我们还没有明确的指针,我们可以用andmyA来做一个吗?ptrmemPtr

4

5 回答 5

4

经过大量的研究...

这实际上是在大多数工业侵入式列表实现中完成的。然而,它确实需要一些hackery。

Boost 侵入式结构使用以下内容(是的,它是特定于实现的)

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
}

本质上与在 linux 内核中使用 container_of 宏来管理侵入列表相同(尽管在 C 中):

#define container_of(ptr, type, member) ({ \
            const typeof( ((type *)0)->member ) *__mptr = (ptr); 
            (type *)( (char *)__mptr - offsetof(type,member) );})
于 2011-07-29T21:40:04.677 回答
3

你没有。指向成员的指针不知道它所属的类的任何实例。这就是为什么当您想通过指针访问成员的任何时候都需要一个实例的原因。

指向成员的指针不是指针。事实上,C++ 委员会甚至称它为指针可能是一个错误。在许多(如果不是大多数)实现中,甚至指针的大小也不等于指向成员的指针的大小。您可以在这里玩任何抵消技巧。即使您找到了一种方法,如果您在指向成员的指针中解析数据,它仍然是特定于该实现的。

于 2011-07-29T01:06:10.983 回答
1

你不能。

指向成员的指针不存储有关任何特定实例的信息。

它只知道一个类型和一个指向该类型内函数的指针。

于 2011-07-29T01:07:12.523 回答
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));

你真的不应该这样做。

于 2011-07-29T01:16:30.997 回答
0

这应该是可能的并且非常有用。只要您确定什么类型的结构包含指向成员的指针,指向成员的指针只是一个偏移量。

于 2015-02-22T20:51:24.963 回答