CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Sep 2004
    Posts
    561

    Multiple Inheritance Problem

    There was a bug that stumped me for a while and I'd like to know the exact reason why this is happening.
    I'm going to simplify the problem here.

    Code:
    class Base1 - Concrete class
    {
    virtual void DoSomething1(){}
    }
     
    class Base2 - Abstract class
    {
    virtual void DoSomething2()=0;
    }
     
    class Derived : Base1, Base2
    {
    void DoSomething1(){}
    void DoSomething2(){}
    }
    When I create a new instance of Derived and call DoSomething2(), the function that gets invoked is DoSomething1()

    However, here is what the root cause appears to be.

    EDIT: Example was slightly off we are casting back to Base2.
    Code:
     
    Derived *d = new Derived();
    DWORD dPtr = (DWORD)d;
    Base2 *b2 = (Base2*) dPtr;
    b2->DoSomething2(); //DoSomething1() is called
    How come casting to a DWORD and then casting back to Derived* screws things up?
    Last edited by Rigel; May 2nd, 2008 at 08:56 PM.

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Multiple Inheritance Problem

    Quote Originally Posted by Rigel
    There was a bug that stumped me for a while and I'd like to know the exact reason why this is happening.
    Obviously DWORDs are not pointers to Derived*, so any type of this back-and-forth C-style casting like this is not guaranteed to work correctly.

    Regards,

    Paul McKenzie

  3. #3
    Join Date
    Sep 2004
    Posts
    561

    Re: Multiple Inheritance Problem

    Quote Originally Posted by Paul McKenzie
    Obviously DWORDs are not pointers to Derived*, so any type of this back-and-forth C-style casting like this is not guaranteed to work correctly.

    Regards,

    Paul McKenzie
    Thanks, but I thought a pointer was just a variable that held a 4 byte integer memory address. I don't see how casting this back and forth can cause so much problem.

  4. #4
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Multiple Inheritance Problem

    No!

    To prove it.

    Create an instance of Derived and then assign that one instance to two pointers, one of type Base1 and another of type Base2. Look at the results in a debugger.

    You will instantly see two different addresses, but they are clearly point to the same instances.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  5. #5
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Multiple Inheritance Problem

    Quote Originally Posted by Rigel
    Thanks, but I thought a pointer was just a variable that held a 4 byte integer memory address. I don't see how casting this back and forth can cause so much problem.
    In C++, and especially multiple inherited classes, casting must be done correctly and carefully. This means casting from compatible types, and using C++ style (not C style) casts to make sure this occurs. You can't just blindly cast to an integer, and then cast back from the integer.

    Without the cast, what error did the compiler give you? Anytime you try and make the compiler shut-up an error by casting, you're digging yourself a big hole (i.e. what you're doing is most likely incorrect).

    Regards,

    Paul McKenzie

  6. #6
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Multiple Inheritance Problem

    Quote Originally Posted by Paul McKenzie
    ...Anytime you try and make the compiler shut-up an error by casting, you're digging yourself a big hole (i.e. what you're doing is most likely incorrect).
    I often tell beginners that a C style cast in a C+ program is equivilant to the following statement:

    Hey you stupid miserable little compiler, I know what should be done because I am great and infallible. Even though you ae tracking every byte of memory, all of the registers, etc you are still incapable of making any good decisions. Therefore you will listen to me without question and do exactly what I say regardless of the consequences.
    Now THAT is a pretty arrogant statement.

    Consider how you would feel if someone talked like that to YOU. It is no wonder that the end result is the compiler getting angry and generating destructive code in retailation.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  7. #7
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Multiple Inheritance Problem

    Quote Originally Posted by TheCPUWizard
    I often tell beginners that a C style cast in a C+ program is equivilant to the following statement:



    Now THAT is a pretty arrogant statement.

    Consider how you would feel if someone talked like that to YOU. It is no wonder that the end result is the compiler getting angry and generating destructive code in retailation.
    The most egregious example is trying to cast a two dimenisonal array of T to a T**.

    There has to be at least 20 or 30 threads on this same error, where the poster casts the two dimenisonal array to keep the compiler quiet. Even seasoned programmers, or at least supposed seasoned programmers, get fooled into doing this cast, just because it "feels natural" and the compiler is being too harsh.

    If you did a search on CodeGuru, you would be surprised at the names that thought previously that doing this cast was safe.

    Regards,

    Paul McKenzie

  8. #8
    Join Date
    Nov 2003
    Posts
    1,405

    Re: Multiple Inheritance Problem

    Quote Originally Posted by Rigel
    How come casting to a DWORD and then casting back to Derived* screws things up?
    Well, you aren't exactly casting back the DWORD to Derived*. You're upcasting from DWORD to Base2*. This upcast is problematic because the compiler lacks information about what type DWORD is. By doing it I would say you're entering the realms of undefined behaviour.

    To fix this you should first restore the actual type of the typeless DWORD, namely Derived*. Then you can perform the upcast to Base2*, like

    Base2 *b2 = (Base2*) ((Derived*)dPtr);
    Last edited by _uj; May 3rd, 2008 at 02:00 PM.

  9. #9
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Multiple Inheritance Problem

    Quote Originally Posted by _uj
    Well, you aren't exactly casting back the DWORD to Derived*. You're upcasting from DWORD to Base2*. This upcast is problematic because the compiler lacks information about what type DWORD is. By doing it I would say you're entering the realms of undefined behaviour.

    To fix this you should first restore the actual type of the typeless DWORD, namely Derived*. Then you can perform the upcast to Base2*, like

    Base2 *b2 = (Base2*) ((Derived*)dPtr);
    I believe that is still undefined behaviour (99.9998%), but much more likely to "randomly" work on 32 Bit Intel boxes at least...
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  10. #10
    Join Date
    Nov 2003
    Posts
    1,405

    Re: Multiple Inheritance Problem

    Quote Originally Posted by TheCPUWizard
    I believe that is still undefined behaviour (99.9998%), but much more likely to "randomly" work on 32 Bit Intel boxes at least...
    You mean assigning a pointer to DWORD (an integer type) is undefined? That's true but if DWORD is replaced by void* it's correct C++ and should be portable.

    Still the problem the OP reports persists also with void*. It has to be fixed the way I suggested, by restoring the typeless pointer to its actual type before upcasting.

    So it's okay to make a pointer typeless by casting it to void*, but be sure to cast it back to its proper type before doing something with it. If not you get undefined behaviour

    This is discussed in 5.6 Pointer to Void in Stroustrups C++ book.
    Last edited by _uj; May 4th, 2008 at 10:17 AM.

  11. #11
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Multiple Inheritance Problem

    Quote Originally Posted by _uj
    You mean assigning a pointer to DWORD (an integer type) is undefined? That's true but if DWORD is replaced by void* it's correct C++ and should be portable.

    Still the problem the OP reports persists also with void*. It has to be fixed the way I suggested, by restoring the typeless pointer to it's actual type before upcasting.

    So it's okay to make a pointer typeless by casting it to void*, but be sure to cast it back to its proper type before doing something with it. If not you get undefined behaviour

    It's discussed in 5.6 Pointer to Void in Stroustrups C++ book.
    To/From a "void *" done properly is 100% defined and your are 100% correct.

    On the other hand, there is NO requirement that DWORD (typically a representation of an integer of a given width) is in any way shape for form compatabile with a pointer. Even on an x64,m I64 machine I would expect it to fail..
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  12. #12
    Join Date
    Sep 2004
    Posts
    561

    Re: Multiple Inheritance Problem

    Quote Originally Posted by _uj
    Well, you aren't exactly casting back the DWORD to Derived*. You're upcasting from DWORD to Base2*. This upcast is problematic because the compiler lacks information about what type DWORD is. By doing it I would say you're entering the realms of undefined behaviour.

    To fix this you should first restore the actual type of the typeless DWORD, namely Derived*. Then you can perform the upcast to Base2*, like

    Base2 *b2 = (Base2*) ((Derived*)dPtr);
    Thanks that's the answer I was looking for.

  13. #13
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Multiple Inheritance Problem

    To/From a "void *" done properly is 100% defined and your are 100% correct.
    Though IMO it should ring a small alarm bell that something could probably be improved in your design. The only reason I've ever had to cast to an intermediate generic type was when passing pointers to data using Windows messages.

  14. #14
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Multiple Inheritance Problem

    Quote Originally Posted by JohnW@Wessex
    Though IMO it should ring a small alarm bell that something could probably be improved in your design.

    Hey I nevr said that it was "good", only that it was well defined. I would most likely "slap someone upside the head [NCIS] unless there was an invariant external constraint.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  15. #15
    Join Date
    Nov 2003
    Posts
    1,405

    Re: Multiple Inheritance Problem

    Quote Originally Posted by JohnW@Wessex
    The only reason I've ever had
    When many "only reasons" are added the total reason can be quite substantial.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured