member to pointer conversions - mommy look what I found

Discussion in 'C++' started by Gianni Mariani, Dec 17, 2003.

  1. 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 ?
     
    Gianni Mariani, Dec 17, 2003
    #1
    1. Advertising

  2. Gianni Mariani

    John Carson Guest

    "Gianni Mariani" <> wrote in message
    news:brp0jl$
    > 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)?


    --
    John Carson
    1. To reply to email address, remove donald
    2. Don't reply to email address (post here instead)
     
    John Carson, Dec 17, 2003
    #2
    1. Advertising

  3. John Carson wrote:
    > "Gianni Mariani" <> wrote in message
    > news:brp0jl$
    >
    >>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


    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.
     
    Gianni Mariani, Dec 17, 2003
    #3
  4. Gianni Mariani

    tom_usenet Guest

    On 17 Dec 2003 02:28:53 EST, Gianni Mariani <>
    wrote:

    >
    >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
     
    tom_usenet, Dec 17, 2003
    #4
  5. Gianni Mariani

    Dan Cernat Guest

    Gianni Mariani <> wrote in message news:<brp0jl$>...
    > 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
     
    Dan Cernat, Dec 17, 2003
    #5
  6. Dan Cernat wrote:
    > Gianni Mariani <> wrote in message news:<brp0jl$>...
    >

    ....
    >>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


    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;
    }



    >
    >
    >> 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.


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

    I confirmed that.
     
    Gianni Mariani, Dec 17, 2003
    #6
  7. Gianni Mariani

    John Carson Guest

    "Gianni Mariani" <> wrote in message
    news:brpan2$
    > John Carson wrote:
    > > "Gianni Mariani" <> wrote in message
    > > news:brp0jl$
    > >
    > > >
    > > > 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

    >
    > 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.

    --
    John Carson
    1. To reply to email address, remove donald
    2. Don't reply to email address (post here instead)
     
    John Carson, Dec 17, 2003
    #7
  8. 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.
     
    Gianni Mariani, Dec 17, 2003
    #8
  9. tom_usenet wrote:
    > On 17 Dec 2003 02:28:53 EST, Gianni Mariani <>
    > 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;
    ....
     
    Gianni Mariani, Dec 17, 2003
    #9
  10. Gianni Mariani

    tom_usenet Guest

    On 17 Dec 2003 14:07:50 EST, Gianni Mariani <>
    wrote:

    >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.


    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
     
    tom_usenet, Dec 18, 2003
    #10
  11. Gianni Mariani

    Dan Cernat Guest

    Gianni Mariani <> wrote in message news:<brpus1$>...
    > Dan Cernat wrote:
    > > Gianni Mariani <> wrote in message news:<brp0jl$>...
    > >

    > ...
    > >>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

    >
    > 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;
    > }
    >
    >
    >
    > >
    > >
    > >> 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.

    >
    > 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.
     
    Dan Cernat, Dec 18, 2003
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fraser Ross
    Replies:
    4
    Views:
    1,058
    Fraser Ross
    Aug 14, 2004
  2. Replies:
    10
    Views:
    709
    Jasen Betts
    Aug 5, 2005
  3. James Aguilar
    Replies:
    3
    Views:
    441
    Frederick Gotham
    Jun 22, 2006
  4. Replies:
    11
    Views:
    503
    Richard Bos
    May 8, 2008
  5. Ersek, Laszlo
    Replies:
    5
    Views:
    353
    Keith Thompson
    Mar 7, 2010
Loading...

Share This Page