member to pointer conversions - mommy look what I found

G

Gianni Mariani

While digging for a work around for a VC++7.1 compiler bug I came to
find an interesting thing about pointer to member conversions.


struct A
{
int a;
};

struct B : A
{
int b;
};

typedef int A::* A_mptr;
typedef int B::* B_mptr;


B_mptr bptr1 = &B::a; // ok no probs

A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

int main()
{
bptr1 = aptr1; // works - a way to get to private members eh?
aptr1 = bptr1; // error - as expected
}

I would have expected that line *** would have created an error but I
can see that in this case the compiler's behaviour is more interesting.

So there is somthing magic about (&B::a) that am object of type B_mptr
just does not have ?
 
J

John Carson

Gianni Mariani said:
While digging for a work around for a VC++7.1 compiler bug I came to
find an interesting thing about pointer to member conversions.


struct A
{
int a;
};

struct B : A
{
int b;
};

typedef int A::* A_mptr;
typedef int B::* B_mptr;


B_mptr bptr1 = &B::a; // ok no probs

A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

int main()
{
bptr1 = aptr1; // works - a way to get to private members eh?
aptr1 = bptr1; // error - as expected
}

I would have expected that line *** would have created an error but I
can see that in this case the compiler's behaviour is more
interesting.

So there is somthing magic about (&B::a) that am object of type B_mptr
just does not have ?

Huh? Quoting from yourself:

B_mptr bptr1 = &B::a; // ok no probs

As for line ***, isn't this just a matter of "B is a A", i.e., B can be
used in any context that A can (but the reverse is not true)?
 
G

Gianni Mariani

John said:
Huh? Quoting from yourself:

B_mptr bptr1 = &B::a; // ok no probs

What's the "huh" for ? data member a is visible in b.

What's even more interesting is that you can to an implicit downcast:

B_mptr bptr2 = &A::a;
As for line ***, isn't this just a matter of "B is a A", i.e., B can be
used in any context that A can (but the reverse is not true)?

exactly.

So this below does an implicit upcast from class B to class A and note
that when trying to do this with member b it fails.

A_mptr aptr1 = &B::a;

I'm simply pointing out that this pointer to member stuff seems to have
been well thought through ( at least in a primary way ). How this
interacts with complex constructs needs a little more study on my part.
 
T

tom_usenet

While digging for a work around for a VC++7.1 compiler bug I came to
find an interesting thing about pointer to member conversions.


struct A
{
int a;
};

struct B : A
{
int b;
};

typedef int A::* A_mptr;
typedef int B::* B_mptr;


B_mptr bptr1 = &B::a; // ok no probs

A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***

No, B::a *is* A::a - no conversion is involved.
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

Right, b was declared in B (and therefore the member pointer has type
int B::*), and there was no conversion from int B::* to int A::*.
int main()
{
bptr1 = aptr1; // works - a way to get to private members eh?

You can convert T A::* to T B::* since B has all of A's members. The
same applies to member function pointers. But you can only access
&A::i where you can access A::i (e.g. inside A and its friends), so
there's no problem.
aptr1 = bptr1; // error - as expected
}

I would have expected that line *** would have created an error but I
can see that in this case the compiler's behaviour is more interesting.

There's no reason to forbid something harmless that might be useful.
So there is somthing magic about (&B::a) that am object of type B_mptr
just does not have ?

Yes, the type of &B::a is not "int B::*" - it is "int A::*".
Name-lookup on B::a finds A::a, and the type of &A::a is "int A::*".

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
D

Dan Cernat

Gianni Mariani said:
While digging for a work around for a VC++7.1 compiler bug I came to
find an interesting thing about pointer to member conversions.


struct A
{
int a;
};

struct B : A
{
int b;
};

typedef int A::* A_mptr;
typedef int B::* B_mptr;


B_mptr bptr1 = &B::a; // ok no probs

A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

int main()
{
bptr1 = aptr1; // works - a way to get to private members eh?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nope, you used structs. if you use classes, the members are private
and this line will not compile
aptr1 = bptr1; // error - as expected
}

I would have expected that line *** would have created an error but I
can see that in this case the compiler's behaviour is more interesting.

So there is somthing magic about (&B::a) that am object of type B_mptr
just does not have ?

I wouldn't bet my money on it, but it has to be because B is derived
from A.

/dan
 
G

Gianni Mariani

Dan said:
....

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nope, you used structs. if you use classes, the members are private
and this line will not compile

That's not what I meant ... here is the example where access to private
members can be violated.

struct A
{
int a;

// allow access to private p
static int A::* make_a_ptr()
{
return &A::p;
}

private:

int p;
};

struct B : A
{
int b;
};


typedef int A::* A_mptr;
typedef int B::* B_mptr;



A_mptr aptr1 = &B::a;
//A_mptr aptr2 = &B::b;

B_mptr bptr1 = &B::a;
B_mptr bptr2 = &A::a;

B_mptr bptr3 = A::make_a_ptr();

// bptr3 accesses a private membe of A

int main()
{
bptr1 = aptr1;
// aptr1 = bptr1;
}


I wouldn't bet my money on it, but it has to be because B is derived
from A.

Tom's post explains that &B::a == &A::a and is an int A::*, not a B::*.

I confirmed that.
 
J

John Carson

Gianni Mariani said:
What's the "huh" for ? data member a is visible in b.

My "huh" referred to your statement.

"So there is somthing magic about (&B::a) that am object of type B_mptr just
does not have?"

You assign &B::a to an object of type B_mptr when you do:

B_mptr bptr1 = &B::a; // ok no probs

so it was not clear to me why you should be emphasising the differences
between the type on the left hand side and the type on the right hand side.

I am guessing now that you were referring to the contrast between the
two lines:

A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

i.e., &B::a and &B::b (which is of type B_mptr) behave differently.
I'm simply pointing out that this pointer to member stuff seems to
have been well thought through ( at least in a primary way ).

Yes, it seems to work nicely.
 
G

Gianni Mariani

John Carson wrote:
....
I am guessing now that you were referring to the contrast between the
two lines:
yep.


A_mptr aptr1 = &B::a; // hmm converts B::a to A::a ***
A_mptr aptr2 = &B::b; // error - spooky - knows it can't do this

i.e., &B::a and &B::b (which is of type B_mptr) behave differently.

<Knit pick alert>

So Tom points out (and it seems confirmed on gcc at least) that &B::a is
NOT of type int B::* but in fact of type int A::* .

In general, the type of &T::a is *really* Y Z::* where Z is the type of
the class that contains the member 'a', and Y obviously is the type of
the member.

This is the magic.
 
G

Gianni Mariani

tom_usenet said:
On 17 Dec 2003 02:28:53 EST, Gianni Mariani <[email protected]>
wrote:
....
You can convert T A::* to T B::* since B has all of A's members. The
same applies to member function pointers. But you can only access
&A::i where you can access A::i (e.g. inside A and its friends), so
there's no problem.

I wasn't suggesting a "problem" per se. I was just suggesting that you
could. (and I have no idea WHY you would want to this)

example:

struct A
{
int a;

// allow access to private p
static int A::* make_a_ptr()
{
return &A::p;
}

private:

int p;
};

....
ap->*(A::make_a_ptr()) = 2;
....
 
T

tom_usenet

John Carson wrote:
...

<Knit pick alert>

So Tom points out (and it seems confirmed on gcc at least) that &B::a is
NOT of type int B::* but in fact of type int A::* .

In general, the type of &T::a is *really* Y Z::* where Z is the type of
the class that contains the member 'a', and Y obviously is the type of
the member.

This is the magic.

It's a natural consequence of name lookup. "T::a" doesn't denote the
member "a" of T, but a name "a" that can be found in the scope of T or
its base classes (of course, names that can be found in the scope of T
or its base classes are members!). Here's an odd example (that some
popular compilers get wrong)

int i;

struct A
{
static int i;
};

struct B
{
static int i;
};

struct C: A, B
{
using B::i;
};

int main()
{
int* p = &C::i;
}

C::i causes name lookup for i in C. There are two i's, however the
using declaration means that B::i is found in the scope of C before
checking A or B.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
D

Dan Cernat

Gianni Mariani said:
That's not what I meant ... here is the example where access to private
members can be violated.

struct A
{
int a;

// allow access to private p
static int A::* make_a_ptr()
{
return &A::p;
}

private:

int p;
};

struct B : A
{
int b;
};


typedef int A::* A_mptr;
typedef int B::* B_mptr;



A_mptr aptr1 = &B::a;
//A_mptr aptr2 = &B::b;

B_mptr bptr1 = &B::a;
B_mptr bptr2 = &A::a;

B_mptr bptr3 = A::make_a_ptr();

// bptr3 accesses a private membe of A

int main()
{
bptr1 = aptr1;
// aptr1 = bptr1;
}




Tom's post explains that &B::a == &A::a and is an int A::*, not a B::*.

I confirmed that.


You shouldn't have gone that distance for that.

class A
{
int a;

public:
A(int n = 0) : a(n)
{}

int* get_a()
{
return &a;
}
};


int main()
{
A myA(10); // a == 10 now
int* p_a = myA.get_a(); // pointer to the private A::a
*p_a = 20; // changes the private A::a

return 0;
}


Yes, I agree with Tom, too.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top