Simple class inheritance question

Discussion in 'C++' started by crea, Apr 4, 2011.

  1. crea

    crea Guest

    I know its simple, but I cannot find the answer from books because its a
    special case.
    Here:
    ///////////////////////
    class A
    {
    public:
    A* a;
    };

    class B : public A
    {
    public:
    int var;
    };

    A a1, a2;

    a1.a = &a2;
    ((B*)a1.a)->var = 77;
    ////////////////
    I compiled and it works.

    How/why can a1.a set B classes member variable's value even though there is
    not even a one object created from B? How is it possible.

    So all objects are from class A and there is no object created from B and we
    are still using B's members. I thought that this var-variable is not even
    allocated from the memory because there is no B object created??
    crea, Apr 4, 2011
    #1
    1. Advertising

  2. crea

    Richard Guest

    [Please do not mail me a copy of your followup]

    Leigh Johnston <> spake the secret code
    <> thusly:

    >On 04/04/2011 23:11, crea wrote:
    >> I know its simple, but I cannot find the answer from books because its a
    >> special case.
    >> Here:
    >> ///////////////////////
    >> class A
    >> {
    >> public:
    >> A* a;
    >> };
    >>
    >> class B : public A
    >> {
    >> public:
    >> int var;
    >> };
    >>
    >> A a1, a2;
    >>
    >> a1.a =&a2;
    >> ((B*)a1.a)->var = 77;
    >> ////////////////
    >> I compiled and it works.me

    >
    >Just because it compiles and seems to work does not mean that it is
    >correct; it is incorrect (a bug) as it invokes UB.
    >
    >>
    >> How/why can a1.a set B classes member variable's value even though there is
    >> not even a one object created from B? How is it possible.

    >
    >It is not possible; what you have written is buggy code.
    >
    >>
    >> So all objects are from class A and there is no object created from B and we
    >> are still using B's members. I thought that this var-variable is not even
    >> allocated from the memory because there is no B object created??

    >
    >You are illegally overwriting stack space which doesn't seem to manifest
    >any ill effects at the moment but may in the future.


    IIRC, the error would manifest itself as a runtime crash if you had
    used dynamic_cast<B *>(a1.a) instead of a C-style cast. The C-style
    cast has no safeguards and basically says "just jam it in there, I
    know what I'm doing (even when I don't)".
    --
    "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download
    <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/>

    Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
    Richard, Apr 5, 2011
    #2
    1. Advertising

  3. crea

    crea Guest

    "Leigh Johnston" <> wrote in message
    news:...
    >
    > Just because it compiles and seems to work does not mean that it is
    > correct; it is incorrect (a bug) as it invokes UB.
    >
    >>
    >> How/why can a1.a set B classes member variable's value even though there
    >> is
    >> not even a one object created from B? How is it possible.

    >
    > It is not possible; what you have written is buggy code.
    >


    Seriously, I am telling the truth: I have Visual C++ 2008, and it compiles
    and lets me to use it as normal parameter after that. If I call
    ((B*)a1.a)->var later on, it will give 77!
    crea, Apr 5, 2011
    #3
  4. crea

    crea Guest

    "crea" <> wrote in message
    news:QJsmp.2193$2...
    >
    > Seriously, I am telling the truth: I have Visual C++ 2008, and it compiles
    > and lets me to use it as normal parameter after that. If I call
    > ((B*)a1.a)->var later on, it will give 77!


    anyway, am happy to know it was not legal coding... because thats what i
    though as well. Maybe not a good idea to learn C++ by just compiling code
    :).
    crea, Apr 5, 2011
    #4
  5. crea

    Ian Collins Guest

    On 04/ 5/11 11:39 AM, crea wrote:
    > "Leigh Johnston"<> wrote in message
    > news:...
    >>
    >> Just because it compiles and seems to work does not mean that it is
    >> correct; it is incorrect (a bug) as it invokes UB.
    >>
    >>>
    >>> How/why can a1.a set B classes member variable's value even though there
    >>> is
    >>> not even a one object created from B? How is it possible.

    >>
    >> It is not possible; what you have written is buggy code.
    >>

    >
    > Seriously, I am telling the truth: I have Visual C++ 2008, and it compiles
    > and lets me to use it as normal parameter after that. If I call
    > ((B*)a1.a)->var later on, it will give 77!


    What part of "Just because it compiles and seems to work does not mean
    that it is correct; it is incorrect (a bug) as it invokes UB." didn't
    you get?

    --
    Ian Collins
    Ian Collins, Apr 5, 2011
    #5
  6. crea

    Paul Guest

    "crea" <> wrote in message
    news:pmrmp.16671$2...
    >I know its simple, but I cannot find the answer from books because its a
    >special case.
    > Here:
    > ///////////////////////
    > class A
    > {
    > public:
    > A* a;
    > };
    >
    > class B : public A
    > {
    > public:
    > int var;
    > };
    >
    > A a1, a2;
    >
    > a1.a = &a2;
    > ((B*)a1.a)->var = 77;
    > ////////////////
    > I compiled and it works.
    >
    > How/why can a1.a set B classes member variable's value even though there
    > is not even a one object created from B? How is it possible.
    >
    > So all objects are from class A and there is no object created from B and
    > we are still using B's members. I thought that this var-variable is not
    > even allocated from the memory because there is no B object created??


    Basically you're dereferencing an uninitialised pointer.

    B* b;
    b->var=77;

    It just happens that the pointer is a member of a class, and you've
    type-casted it. The pointer could point to anything. °_°
    Paul, Apr 5, 2011
    #6
  7. crea

    Richard Guest

    [Please do not mail me a copy of your followup]

    Leigh Johnston <> spake the secret code
    <> thusly:

    >On 05/04/2011 00:05, Richard wrote:
    >> [Please do not mail me a copy of your followup]
    >>
    >> Leigh Johnston<> spake the secret code
    >> <> thusly:
    >>
    >>> On 04/04/2011 23:11, crea wrote:
    >>>> I know its simple, but I cannot find the answer from books because its a
    >>>> special case.
    >>>> Here:
    >>>> ///////////////////////
    >>>> class A
    >>>> {
    >>>> public:
    >>>> A* a;
    >>>> };
    >>>>
    >>>> class B : public A
    >>>> {
    >>>> public:
    >>>> int var;
    >>>> };
    >>>>
    >>>> A a1, a2;
    >>>>
    >>>> a1.a =&a2;
    >>>> ((B*)a1.a)->var = 77;
    >>>> ////////////////
    >>>> I compiled and it works.me
    >>>
    >>> Just because it compiles and seems to work does not mean that it is
    >>> correct; it is incorrect (a bug) as it invokes UB.
    >>>
    >>>>
    >>>> How/why can a1.a set B classes member variable's value even though there is
    >>>> not even a one object created from B? How is it possible.
    >>>
    >>> It is not possible; what you have written is buggy code.
    >>>
    >>>>
    >>>> So all objects are from class A and there is no object created from B and we
    >>>> are still using B's members. I thought that this var-variable is not even
    >>>> allocated from the memory because there is no B object created??
    >>>
    >>> You are illegally overwriting stack space which doesn't seem to manifest
    >>> any ill effects at the moment but may in the future.

    >>
    >> IIRC, the error would manifest itself as a runtime crash if you had
    >> used dynamic_cast<B *>(a1.a) instead of a C-style cast. The C-style
    >> cast has no safeguards and basically says "just jam it in there, I
    >> know what I'm doing (even when I don't)".

    >
    >Not quite; a dynamic_cast downcast requires a polymorphic type.


    By that I infer you mean that A must have at least one virtual method?

    Yes, that seems reasonable for dynamic_cast<> to work properly.

    All this "just jam it in there" behavior with C-style casts is why I
    consider them a code smell in C++ code.
    --
    "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download
    <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/>

    Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
    Richard, Apr 5, 2011
    #7
  8. On 5 Apr., crea wrote:
    > Seriously, I am telling the truth: I have Visual C++ 2008, and it compiles
    > and lets me to use it as normal parameter after that. If I call
    > ((B*)a1.a)->var later on, it will give 77!


    VisualC 6.0 gives you an Access Violation when you try access
    ((B*)a1.a)->var, most probably because VC6.0 puts the two local
    variables a1 and a2 in a different order on the stack. If you exchange
    the roles of a1 and a2, you can access ((B*)a1.a)->var without Access
    Violations but you'll get a corrupted stack (which results in an
    Access Violation upon exit of main).

    Regards,
    Stuart
    Stuart Redmann, Apr 5, 2011
    #8
  9. crea

    crea Guest

    "Stuart Redmann" <> wrote in message
    news:...
    > On 5 Apr., crea wrote:
    >> Seriously, I am telling the truth: I have Visual C++ 2008, and it
    >> compiles
    >> and lets me to use it as normal parameter after that. If I call
    >> ((B*)a1.a)->var later on, it will give 77!

    >
    > VisualC 6.0 gives you an Access Violation when you try access
    > ((B*)a1.a)->var, most probably because VC6.0 puts the two local
    > variables a1 and a2 in a different order on the stack. If you exchange
    > the roles of a1 and a2, you can access ((B*)a1.a)->var without Access
    > Violations but you'll get a corrupted stack (which results in an
    > Access Violation upon exit of main).
    >


    Yes you are right, I did not run the program to the end, just debugged
    partly, so did not notice this.

    It all makes sense...
    crea, Apr 5, 2011
    #9
  10. crea

    Goran Guest

    On Apr 5, 12:11 am, "crea" <> wrote:
    > I know its simple, but I cannot find the answer from books because its a
    > special case.
    > Here:
    > ///////////////////////
    > class A
    > {
    > public:
    >  A* a;
    >
    > };
    >
    > class B : public A
    > {
    > public:
    >  int var;
    >
    > };
    >
    > A a1, a2;
    >
    > a1.a = &a2;
    > ((B*)a1.a)->var = 77;
    > ////////////////
    > I compiled and it works.


    It does not, it only looks as if it works. First off, if you debug
    through this with visual studio, it should tell you that you corrupted
    the stack. Did you try that? Also, try this:

    1. add B() : var(1) {} to class B
    2. try then this code:

    if (((B*)a1.a)->var != 1)
    cout << "UB baby!";

    you will hit cout. If you really had B behind a1.a, how would that be
    possible? Clearly B::var is 1, isn't it?


    > How/why can a1.a set B classes member variable's value even though there is
    > not even a one object created from B? How is it possible.


    Because you lied to the compiler when you used the cast to B*. In this
    case, cast amounted to static_cast (I think). With static_cast, it's
    your duty to make sure that object you're casting __from__ indeed is
    the of the type you're casting __to__. But a1.a is of type A*, not B*.
    If you fail to observe this rule, it's your fault.

    > So all objects are from class A and there is no object created from B andwe
    > are still using B's members. I thought that this var-variable is not even
    > allocated from the memory because there is no B object created??


    This is correct. var is not allocated because no B has been allocated.
    You managed to write into memory that wasn't allocated for you, and
    that happened because you lied when you used the cast. Don't lie.

    Goran.

    P.S. In general, C-style casts should not be used in C++. Use of
    appropriate C++-style casts makes intention clearer (but using e.g.
    static_cast in your case leads to same problem; lying doesn't pay off).
    Goran, Apr 5, 2011
    #10
  11. crea

    Paul Guest

    "Paul" <> wrote in message
    news:zMtmp.12497$2...
    >
    > "crea" <> wrote in message
    > news:pmrmp.16671$2...
    >>I know its simple, but I cannot find the answer from books because its a
    >>special case.
    >> Here:
    >> ///////////////////////
    >> class A
    >> {
    >> public:
    >> A* a;
    >> };
    >>
    >> class B : public A
    >> {
    >> public:
    >> int var;
    >> };
    >>
    >> A a1, a2;
    >>
    >> a1.a = &a2;
    >> ((B*)a1.a)->var = 77;
    >> ////////////////
    >> I compiled and it works.
    >>
    >> How/why can a1.a set B classes member variable's value even though there
    >> is not even a one object created from B? How is it possible.
    >>
    >> So all objects are from class A and there is no object created from B and
    >> we are still using B's members. I thought that this var-variable is not
    >> even allocated from the memory because there is no B object created??

    >
    > Basically you're dereferencing an uninitialised pointer.
    >
    > B* b;
    > b->var=77;
    >
    > It just happens that the pointer is a member of a class, and you've
    > type-casted it. The pointer could point to anything. °_°


    Sorry I overlooked the a1.a = &a2; assginement , my bad.
    Paul, Apr 5, 2011
    #11
  12. crea

    MikeWhy Guest

    "crea" <> wrote in message
    news:QJsmp.2193$2...
    >
    > "Leigh Johnston" <> wrote in message
    > news:...
    >>
    >> Just because it compiles and seems to work does not mean that it is
    >> correct; it is incorrect (a bug) as it invokes UB.
    >>
    >>>
    >>> How/why can a1.a set B classes member variable's value even though there
    >>> is
    >>> not even a one object created from B? How is it possible.

    >>
    >> It is not possible; what you have written is buggy code.
    >>

    >
    > Seriously, I am telling the truth: I have Visual C++ 2008, and it compiles
    > and lets me to use it as normal parameter after that. If I call
    > ((B*)a1.a)->var later on, it will give 77!


    Seriously, we're not the ones with the miscomprehension. Your code works,
    insofar as it explicitly discards type checking with a C-style typecast. The
    question is what happens if you change B as follows:

    class B : public A
    {
    public:
    char foo[1024];
    int var;
    };

    If it still doesn't fail, make foo even larger. You should conclude from
    this that only a fool subverts type checking. If you rewrite your code to
    honor the type, ...

    B* b = a1.a; // fails. A is not a B.
    b->var = 77;

    .... the compiler should complain appropriately. Ignore or subvert at your
    own peril.
    MikeWhy, Apr 5, 2011
    #12
    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. maxw_cc
    Replies:
    1
    Views:
    3,120
    Martijn van Steenbergen
    Dec 21, 2003
  2. E11
    Replies:
    1
    Views:
    4,719
    Thomas Weidenfeller
    Oct 12, 2005
  3. cppsks
    Replies:
    0
    Views:
    806
    cppsks
    Oct 27, 2004
  4. Doug
    Replies:
    1
    Views:
    388
  5. johnsonlau
    Replies:
    1
    Views:
    763
    Kai-Uwe Bux
    Jul 21, 2008
Loading...

Share This Page