9

Suppose I have two classes:

class A
{
    int x;
    int y;
};


class B
{
    int z;
    A ref;
};

Suppose I also have a function that accepts a pointer-to-member integer of B, like so:

void doSomethingToB(B* object, int B::* val)
{
    if(val)
    {
        std::cout << object.*val;
    }
}

Would there be a way that I could point to a member of ref inside B?

Like, int B::* ptr = &(B::ref.x) or something similar?

Serge
  • 1,974
  • 6
  • 21
  • 33
  • If you have a pointer to `B` why would you need pointers to it's members? – Aesthete Aug 06 '12 at 23:22
  • 1
    @Aesthete Because the real situation is templated, and involves executing the same set of code across a variety of members of a generic class. So I'll just use an array of pointer-to-members, instead of having to rewrite the looping code for multiple members, with no other changes. – Serge Aug 06 '12 at 23:27

2 Answers2

5

This question gets asked from time to time

Is Pointer-to- " inner struct" member forbidden?

Basically, this can be described is a rather obvious initial oversight in the design of C++ language, which has has been ignored ever since due to the fact that the language develops in higher-level directions. Pointers of pointer-to-data member type are probably considered too low-level to be given enough attention. I wouldn't be surprised to discover one day that such pointers are deprecated instead of being developed further.

To repeat my statement from the linked answer, the low-level support is already there in every C++ compiler (since the low-level mechanism is the same regardless how deeply the member is "nested" - it is simply the offset of the member on the containing object), but the corresponding initialization syntax is missing.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Thanks. Is there no way to write in to... whatever the C++ standards committee is called... and offer suggestions, requests, and what not? Also, yeah, the language seems to be moving towards higher level... I'm one of those quirky, often-frowned-upon people who like to use C++ for some of it's things, and use C for others. I like the lower level side of things, and (for shame) I avoid using std:: anything, if I can. Maybe, once C++ goes too far high level, someone will write dialect of C for the in-between people like myself (Yeah, right). – Serge Aug 06 '12 at 23:41
  • Also, sorry for repeat question! – Serge Aug 06 '12 at 23:42
  • 1
    It's easy to get a pointer from B to A's x if you use inheritance rather than composition. Also in this particular case I agree with your statement about the offset, but once you start getting virtual base classes involved then I think things start getting hairy. – Neil Aug 06 '12 at 23:49
  • @Serge: I have to agree with Neil, in the simple cases the approach to a pointer-to-inner member is simple, but things get more complicated. In particular, it would be impossible to have pointer to member where the member is an object with a virtual base. The problem is that the information needed would be increasingly larger. For a regular pointer to member you need an offset or possibly an offset from an entry in the vtable (`sizeof` a pointer to member is usually a couple of pointers wide). If you allowed for members of members, you would need to double the size of that for each... – David Rodríguez - dribeas Aug 07 '12 at 01:28
  • @David Rodríguez - dribeas: It don't see how the information would get larger for member *data* pointers specifically. In all cases `M T::*` is just an *offset* from the beginning of the complete object of type `T`. Nothing else. Virtual inheritance doesn't change this at all. Regardless of the inheritance type, any member subobject has a well-defined specific offset from the beginning of the full object. – AnT stands with Russia Aug 07 '12 at 01:32
  • When it does get more complicated is when we start *converting* such pointers up and down the hierarchy, i.e. use the contra-variance properties of member pointers. However, with data member pointers it is all doable even in virtual inheritance hierarchy (unless we run into ambiguities). Again, data member pointers are fully resolved at the point of initialization, which makes virtual inheritance a non-issue. No need to make them large. It is member *function* pointers that can get really complicated and therefore require extra info. But not member data pointers. – AnT stands with Russia Aug 07 '12 at 01:35
  • @AndreyT: Currently the size of a pointer to member is twice the size of a pointer. Basically, for a regular type you need just an offset from the start of the object, but if there is any virtual base, then the pointer to member has to store the offset of the pointer to the base (in the vtable) and the offset from the start of the base to the member. If you allowed for pointers to member of member, then you would potentially need an offset from your vtable to find the base, then an offset from that to find the member, and then an offset from that member to it's own member (with the potential.. – David Rodríguez - dribeas Aug 07 '12 at 01:38
  • .. extra step to allow for virtual bases) The problem is that to locate a member, an offset does not suffice. – David Rodríguez - dribeas Aug 07 '12 at 01:39
  • @David Rodríguez - dribeas: In all implementations I tried the size of member data pointer is *the same* as the size of ordinary pointer. You must be thinking about member *function* pointers, which are indeed twice the size and which are a completely different story. As far as I understand, the language simply prohibits member pointer contra-variance through virtual inheritance boundaries. For this reason, the issue of converting such pointers across virtual inheritance simply does not exist. It is simply beside the point in this discussion. – AnT stands with Russia Aug 07 '12 at 01:46
  • @Neil: Contra-variant conversions of member pointers are simply prohibited by the language, so the virtual inheritance is really non-issue within the topic of the original question. Or, if you will, it is a completely different issue. – AnT stands with Russia Aug 07 '12 at 01:51
  • @AndreyT: My bad, you are right. I had just run a test to confirm, and did not realize that I was compiling in 64bit mode, mistakenly interpreting `8` as the size of 2 pointers. – David Rodríguez - dribeas Aug 07 '12 at 02:32
-1

Would not just use a plain int* pointer? Why does it need to be a member pointer?

void doSomethingToVal(int * val) 
{ 
    if(val) 
    { 
        std::cout << *val; 
    } 
} 

int *ptr = &(B::ref.x);
doSomethingToVal(ptr) ;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    In practice, for what I currently need, yes, I could just use some `int*`s. But, in theory, I think it's still an interesting question to ask! I gotta learn more! – Serge Aug 06 '12 at 23:30
  • 2
    How about: because it is a completely different thing. Functionality-wise, ordinary pointer cannot replace member pointer. member pointers implement the concept of "offset" and can be applied to different objects. Ordinary pointer cannot replace that. – AnT stands with Russia Aug 06 '12 at 23:32
  • actually, now that I look back at it, I can't use regular int*s. Still working with offsets. Although, I suppose I could do some custom offsetting... Who knows what evil will lurk when I attempt this? Also: I won't know if I'm working with an inherited or base class! Fun! – Serge Aug 07 '12 at 00:13