6

I know that I can get a pointer to data member for a class or struct but the last line of the following code fails to compile:

struct abc
{
    int a;
    int b;
    char c;
};

int main()
{
    char abc::*ptt1 = &abc::c;
    void *another_ptr = (void*)ptt1;
}

Why can't I convert ptt1 to another_ptr? We're talking about pointers so one pointer should have a similar dimension to another one (although conceptually different)?

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Paul
  • 725
  • 1
  • 6
  • 15
  • What is the error message? – Suvarna Pattayil Mar 21 '13 at 12:20
  • I'm using MSVC2012: error C2440: 'type cast' : cannot convert from 'char abc::* ' to 'void *' – Paul Mar 21 '13 at 12:21
  • Check out the answer to [the top related question to the right](http://stackoverflow.com/questions/1307278/casting-between-void-and-a-pointer-to-member-function?rq=1). – molbdnilo Mar 21 '13 at 12:22
  • Don't use c-casts in c++. Stick to c++ casts (in this case reinterpret_cast). – RedX Mar 21 '13 at 12:24
  • 3
    @RedX: but you can't choose a C++ cast until you know what kind of conversion it is. And in this case you can't know what kind of conversion it is, because there is no conversion available of any kind :-) – Steve Jessop Mar 21 '13 at 12:25

3 Answers3

10

A pointer to non-static class member type is not the same as a object pointer type; they behave very differently. In fact, you cannot even dereference a pointer to member with *. To access a member through a pointer to member, you use the .* and ->* operators instead. If you could cast it to an object pointer type like this, what would happen, then, if you dereferenced it with *?

Only object pointer types have a standard conversion to void* (§4.10):

A prvalue of type "pointer to cv T," where T is an object type, can be converted to a prvalue of type "pointer to cv void".

They're so different that the standard even goes out of its way to make sure that the term "pointer" doesn't include pointers to non-static members (§3.9.2):

Except for pointers to static members, text referring to "pointers" does not apply to pointers to members.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • About the only thing you can do with a `void*` is to cast it back to the original type anyway, so the question of possible use isn't necessarily valid. You can't dereference a `void*` with `*` either. – James Kanze Mar 21 '13 at 12:38
  • Except that it's still not clear what you mean by "normal pointers". Only pointers to objects (in the C++ sense) can be converted to `void*`. Pointers to members and pointers to functions cannot. – James Kanze Mar 21 '13 at 13:41
  • @JamesKanze Okay, I've used standard terms now. – Joseph Mansfield Mar 21 '13 at 13:52
2

The main reason is because there is no requirement that a pointer to member have the same size and representation as a pointer to data. In practice, it's hard to imagine a pointer to a data member not being able to fit into a void*, since a pointer to a data member really only needs to contain an offset. Roughly speaking, a pointer to a data member will never need to be larger than a size_t, and a void* must be at least as large as a size_t. On the other hand, it could easily contain bit patterns which weren't legal in a pointer. In fact, as Steve Jessop points out, pointers to member do require additional information, since if the member is in a virtual base, its offset depends on the most derived class, and must be calculated dynamically, based on additional information in the pointer.

More generally, a void* can only contain a pointer to data. It must be as large as the largest data pointer (typically a char*), but pointers to functions, and member pointers, can be larger, and not fit (and pointer to member functions almost never fit).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • "a pointer to a data member really only needs to contain an offset" - unless the member is in a virtual base class, in which case more is needed (I think. Am I wrong, is it only with pointer-to-member-function that it's difficult?). – Steve Jessop Mar 21 '13 at 12:39
  • 1
    @SteveJessop You're right. I don't know where I'd seen it presented as a simple offset. With VC 2012, 32 bit mode, `int*` has a size of 4, `int Class::*` 12. (Come to think about it, I think the last time I'd actually looked at it in detail was before multiple inheritance was added to the language. And then, the only difficulty is virtual functions.) – James Kanze Mar 21 '13 at 14:08
0

Are you trying to do something like this?

struct ABC
{
    int a;
    int b;
    char c;
};

int main()
{
    ABC abc;
    char *ptt1 = &abc.c;
    void *another_ptr = (void*)ptt1;
}
Steve Wellens
  • 20,506
  • 2
  • 28
  • 69