3

C++ имеет static_cast для преобразования base_class_pointer в derived_class_pointer.Преобразование C++: иметь указатель на объект, вычислять указатель на объект

Очень похожая операция для преобразования object_data_member_pointer в object_pointer.

Я написал функцию ConvertDataMemberPtrToObjectPtr с использованием небезопасного преобразования типа C.

  • Как это можно сделать безопасным способом? Ссылка на элемент должна быть указана как параметр шаблона member_ptr.
  • Могут ли быть какие-либо проблемы, если вы используете такую ​​реализацию?

Источник:

#include <stdio.h> 
#include <tchar.h> 

template< class T, class Member_type, Member_type T::*member_ptr > 
inline T *ConvertDataMemberPtrToObjectPtr(Member_type& member) {  
    //Got reference to member 'member' of object 'T', return pointer to object 'T' 
    // obj_ptr = member_ptr - offset_of_member_field 
    return (T*) (((char*)(&member)) - ((char*) ( &(((T*)(0))->*member_ptr)) )); 
} 

struct Test { 
    int a; 
    int b; 
}; 

int _tmain(int argc, _TCHAR* argv[]) { 

    Test obj; 

    printf("\n0x%08lX", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::a>(obj.a)); 
    printf("\n0x%08lX", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::b>(obj.b)); 

    // This is must be avoided when using ConvertDataMemberPtrToObjectPtr!!! 
    printf("\n0x%08lX - error!", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::a>(obj.b)); 

    return 0; 
} 

Использование родителей вместо членов и static_cast:

template <class T, int id=0> 
class Link { 
public: 
    int value; 
    T *GetObjectPtr() { return static_cast<T*>(this); } 
}; 
enum MyLinkId { Main=0, Red=1 }; 
class MyItem : public Link<MyItem,Main>, public Link<MyItem,Red> {}; 

MyItem x; 
Link<MyItem,Main> *p2 = &x; 
Link<MyItem,Red> *p3 = &x; 

printf("\n0x%08lX", p2->GetObjectPtr()); 
printf("\n0x%08lX", p3->GetObjectPtr()); 
+0

Почему бы не использовать 'obj' напрямую, так как у вас есть это? Если вы не можете в своем реальном коде, то уродливые броски - ваш единственный курорт. – uk4321

+0

Я рассматриваю случай, описанный в шаблоне. Я думаю, что это преобразование иногда может быть полезным. В моей проблеме я решил использовать множественное наследование и 'static_cast'. – stan5

+0

Доступ к значению через MyItem будет неоднозначным! –

ответ

2

То, что вы пытаетесь достичь невозможно: Информация отличить членов отсутствует. Вам понадобится уникальный ссылочный элемент, который вы можете передать в свою функцию преобразования.

struct UniqueReferenceMember {}; 
struct Test { 
    UniqueReferenceMember unique_reference_member; 
    int a; 
    int b; 
}; 

Наличие этого бессмысленно. Существует указатель объекта, который вы можете передать напрямую (возможно, преобразован в void *);

+0

Я хочу избежать «небезопасного преобразования типа C» в 'return (T *) ...'. Мне кажется, что ваш ответ о 'printf (" \ n0x% 08lX - error! "...' проблема, но это не моя точка. – stan5

+0

Нет. Я обращаюсь к вашей попытке отличить участников. –

Смежные вопросы