CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 3 123 LastLast
Results 1 to 15 of 36
  1. #1
    Join Date
    Dec 2003
    Posts
    112

    Multiple Inheritance and Casting

    I have a circumstance where multiple inheritance is required. I have a class layout something like the following.

    Code:
    class Mode
    {
    
    }
    
    class ModeType1 : Mode
    {
    }
    
    class ModeType2 : Mode
    {
    }
    
    class SpecialModeCommon
    {
    }
    
    
    class SpecialModeType1 : ModeType1, SpecialModeCommon
    {
    }
    
    class SpecialModeType2 : ModeType2, SpecialModeCommon
    {
    }
    
    class ModeManager
    {
      static Mode* GetMode();
    }
    Now, I need to use GetMode() to access the mode but I need to cast it to SpecialModeCommon in order to access some of the special methods/objects. At the point where I am doing this I can be sure that the Mode is also of type SpecialModeCommon.

    The following will not compile since SpecialModeCommon does not extend Mode.

    Code:
    SpecialModeCommon* mode = static_cast<SpecialModeCommon*>(ModeManager::GetMode());
    I can do a C style cast to get it to compile but that results in data being written to odd places and things not working.

    For some reason not understood by me, dynamic_cast does not work in the environment I am working in. I don't understand why but assume I don't have dynamic_cast available (would that even solve this problem?)

    Any assistance would be appreciated.
    Eggman
    Using: VS 2008 w. Net 3.5

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

    Re: Multiple Inheritance and Casting

    Quote Originally Posted by Eggman002 View Post
    I have a circumstance where multiple inheritance is required.
    Note that class uses private inheritance by default. To get public inheritance you need to declare that explicitly, like

    Code:
    class ModeType1 : public Mode
    And try to avoid downcasting if you can.
    Last edited by _uj; January 13th, 2009 at 05:20 PM.

  3. #3
    Join Date
    Feb 2002
    Posts
    4,640

    Re: Multiple Inheritance and Casting

    Well, look at your return type. It's a "Mode" pointer, totally unrelated to a "SpecialMode" pointer. What if your ModeManager has regular Mode objects (nothing inherited from SpecialModeCommon)?

    I haven't looked into it too deeply, but my guess is that your mode manager is storing modes only. dynamic_cast has no way of knowing if any of the modes stored are pointers to objects that are derived from SpecialMode.

    If you cannot re-factor this data structure, perhaps you could create a "GetSpecialMode" function, and add a data member to your ModeManager that stores SpecialMode objects. Or, create a "SpecialModeManager"?

    Viggy

  4. #4
    Join Date
    Nov 2007
    Location
    Birmingham, England
    Posts
    157

    Re: Multiple Inheritance and Casting

    Quick answer
    You can't do what you're trying here because SpecialModeCommon is not a Mode and Mode is not a SpecialModeCommon.

    The quick fix is make SpecialModeCommon inherit from Mode thus removing the need for multiple inheritance.



    Explanation

    Think of inheratance a different way for a second.
    Code:
    class A {};
    
    class B : public A {};
    
    // ...
    B * SomeB;
    A * SomeA = SomeB;
    is implamented as
    Code:
    class A{};
    
    class B {
        A inheratedA;
    };
    
    // ...
    B * SomeB;
    A * SomeA = &(SomeB->inheratedA);



    Now for something more complicated:
    Code:
    class A {};
    class B {};
    class C {};
    
    class Test1 : A, B, C {};
    class Test2 : A, C {};
    Gets Implamented as
    Code:
    class A {};
    class B {};
    class C {};
    
    class Test1 {
        A InheritedA;
        B InheritedB;
        C InheritedC;
    };
    
    class Test2 {
        A InheritedA;
        C InheritedC;
    };
    With this you can go from Test1 to C (change the memory pointer to point to "inheratedC").

    You can also go from C to Test1 easily (assume the pointer points to inheratedC so change it to point to the start of the object).

    But you can not go from A to C.
    How would you get there?
    Is there a B inbetween or not?

    The compiler simply doesnt know.

    If you use C-style casting you can get it to compile, but the compiler wont change the pointer when you cast so it will read/write to the wrong fields.




    Hope this is of some help.

    Regards
    Signature
    Please use: [ code ][/ code ] tags and reasonably correct tabbing. They really help us read your code
    End Signature

  5. #5
    Join Date
    Dec 2003
    Posts
    112

    Re: Multiple Inheritance and Casting

    Quote Originally Posted by _uj View Post
    Note that class uses private inheritance by default. To get public inheritance you need to declare that explicitly
    That was just due to a sloppy rewrite of the code. I was using public.

    As for the rest of the comments, that is sort of what I figured and yet I am not sure there is a nice way to change around the application. I have thought about having SpecialModeCommon inherit from Mode but then I end up with a diamond pattern for my inheritance tree where two branches of the inheritance both inherit from Mode. That has it's own set of issues.

    It doesn't entirely solve the problem but suppose I were to take the result of GetMode and cast it to SpecialModeType1 (Where the returned mode is actually of type SpecialModeType1) and then from there cast it again into SpecialModeCommon (which should now be a valid cast). Would something like that work? Doing that defeats the purpose of having SpecialModeCommon but I am just curious if it would work.

    Now if I was writing this in C#, the equivalent would be if SpecialModeCommon was an Interface. In this case I believe C# would let me do the cast something like:

    Code:
    ISpecialModeCommon m = ModeManager.GetMode() as ISpecialModeCommon;
    
    if(m != null)
    {
      // m must be of type ISpecialModeCommon
    }
    or

    Code:
    Mode m = ModeManager.GetMode();
    
    if(m is ISpecialModeCommon)
    {
      ISpecialModeCommon sm = mode as ISpecialModeCommon
    }
    Does C++ not have anything equivalent?
    Eggman
    Using: VS 2008 w. Net 3.5

  6. #6
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    Re: Multiple Inheritance and Casting

    You can use dynamic_cast to try downcasting.

    Code:
    ISpecialModeCommon* m = dynamic_cast<ISpecialModeCommon*>( ModeManager.GetMode() );
    if( NULL != m )
    {
        // do something with m
    }
    Edit:
    Typo fixed
    Last edited by GNiewerth; January 14th, 2009 at 07:53 AM.
    - Guido

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

    Re: Multiple Inheritance and Casting

    Quote Originally Posted by Eggman002 View Post
    and yet I am not sure there is a nice way to change around the application.
    I think this is the wrong approach. Instead think about what the different types (classes) represent and what relationships you want to express. What are all these "modes" you're trying to fit into an inheritance hierarchy?

    And in principle a downcast represents a design failure so try to avoid that. Checking objects for type and then make special provisions based on type is bad design (in C++ as well as in C#).

  8. #8
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Multiple Inheritance and Casting

    Sorry for posting an off topic response, but couling, you do not have private messaging enabled... anyway, you are missing an 'e' off of coffee in your signature.

    Eggman002, I understand why your structure is the way it is, but at the same time I don't like it. Although you could argue that your structure has an is-a relationship, in my opinion is smacks as a structure designed for code re-use.

    I would seriously reconsider your design. What is the difference in functionality between ModeType1 and ModeType2 for example?
    Last edited by PredicateNormative; January 14th, 2009 at 09:57 AM. Reason: Removed a stupid idea.

  9. #9
    Join Date
    Nov 2007
    Location
    Birmingham, England
    Posts
    157

    Re: Multiple Inheritance and Casting

    Examples of code that need a class design such as you're suggesting are very rare. Most people considder them bad design.

    Having never used them myself I'm going to tentatively suggest using a virtual base class.

    Beyond this, a design really can't be sudgested as it isnt clear why you chose this design. If you'd like a hand with re-factoring then you will need to share a little more infomation about your constraints (the reason why you chose this design based on what you're trying to build)

    Regards

    _____________________________________
    PredicateNormative:
    couling <-- dyslexic. But thanks for letting me know.
    Signature
    Please use: [ code ][/ code ] tags and reasonably correct tabbing. They really help us read your code
    End Signature

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

    Re: Multiple Inheritance and Casting

    I have to agree with the others in that this appears to be an abuse of inheritance. Whanting to eliminate code duplication is never a reason for public inheritance.

    This seems more like a situation that would use aggregation/composition.

    I did want to point out that couling's post with the use of members instead of inheritance is a good one, and that there IS a way to reliabily "get from A to C" regardless of if the instance is a Test1 or Test2....

    Simple create a singleton map that std::map<A*,C*> and have your classes register the apppropriate addresses in the map (dont forget to unregister in the destructor!!!

    Now you can quickly see if "An instance of A has a related instance of C"
    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

  11. #11
    Join Date
    Dec 2003
    Posts
    112

    Re: Multiple Inheritance and Casting

    Well suffice it to say that I didn't write all the code, I just have to modify it.

    So in my example, Mode, ModeType1, ModeType2 and ModeManager are written by someone else and can not be easily modified without potentially breaking everything.

    I have created SpecialModeType1 and SpecialModeType2 to provide some increased functionality above and beyond what is in ModeType1 and ModeType2.

    These two special modes have common functions so it seems like they should inherit from a common source.

    Basically I am trying to avoid having to to something like:

    Code:
    if(verify that we are in SpecialMode1)
    {
      // Access Data from SpecialMode1
    }
    else if(verify that we are in SpecialMode2)
    {
      // Access Data From SpecialMode2
    }
    Instead I want to do:

    Code:
    if(verify that we are in SpecialMode1 or SpecialMode2)
    {
      // Access Data From SpecialModeCommon
    }
    Eggman
    Using: VS 2008 w. Net 3.5

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

    Re: Multiple Inheritance and Casting

    All comments in this post refer to public inheritance...

    Quote Originally Posted by Eggman002 View Post
    These two special modes have common functions so it seems like they should inherit from a common source.
    No, no, no... Now go to your blackboard, pick up some chalk, and write 100 times "I will never think about using inheritance to share code".

    Inheritcance is for strictly IS-A relationships. Presuming you have comprehensive documentation on all of the classes, you MUST be able to take all of the documentation for both SpecialModeCommon, Mode, and ModeType1
    then do a search/replace with SpecialModeType1 in the three sets of documents.

    If the resulting three documents contain a single inaccuracy, then either your documentation is wrong, or inheritance is NOT appropriate.

    If you want to "share implementation" then use aggregation:

    psuedo code...
    Code:
    class SpecialModeCommon
    {
    public:
        void ACommonFunction() {}
    }
    
    class SpecialModeType1 : ModeType1
    {
    private:
        SpecialModeCommon m_Common;
    
    public:
         void ACommonFunction()
          {
               m_Common.ACommonFunction();
          }
    }
    
    SpecialModeType2 : ModeType2
    {
    private:
        SpecialModeCommon m_Common;
    
    public:
         void ACommonFunction()
          {
               m_Common.ACommonFunction();
          }
    }
    Last edited by TheCPUWizard; January 14th, 2009 at 09:28 AM. Reason: typo in tags...
    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

  13. #13
    Join Date
    Dec 2003
    Posts
    112

    Re: Multiple Inheritance and Casting

    Quote Originally Posted by TheCPUWizard View Post
    If you want to "share implementation" then use aggregation:

    psuedo code...
    Code:
    class SpecialModeCommon
    {
    public:
        void ACommonFunction() {}
    }
    
    class SpecialModeType1 : ModeType1
    {
    private:
        SpecialModeCommon m_Common;
    
    public:
         void ACommonFunction()
          {
               m_Common.ACommonFunction();
          }
    }
    
    SpecialModeType2 : ModeType2
    {
    private:
        SpecialModeCommon m_Common;
    
    public:
         void ACommonFunction()
          {
               m_Common.ACommonFunction();
          }
    }
    The problem with that solution (unless I am missing something) is that I then have to do the following:

    Code:
    if(Verify we are in SpecialModeType1)
    {
      SpecialModeType1* mode = static_cast<SpecialModeType1*>(ModeManager::GetMode());
      mode->ACommonFunction();
    }
    else (Verify we are in SpecialModeType2)
    {
      SpecialModeType2* mode = static_cast<SpecialModeType2*>(ModeManager::GetMode());
      mode->ACommonFunction();
    }
    Now it might just be me but it seems like the fact that I have the same line of code repeated is silly (i.e. mode->ACommonFunction()).

    In a simple example like this it isn't a big deal but in a more complex example where this code may be getting called in many places and may be calling more than just one common function, this could get messy.

    I suppose it doesn't matter since that is essentially what I wound up having to do in order to get it to work, but it seems wasteful.
    Eggman
    Using: VS 2008 w. Net 3.5

  14. #14
    Join Date
    Nov 2007
    Location
    Birmingham, England
    Posts
    157

    Re: Multiple Inheritance and Casting

    The problem is that this isnt really possible. The best sugestion for what you want was to create a map (as suggested by TheCPUWizard earlier).

    You need a way to get from a Mode to SpecialModeCommon. This can not be done directly with inheritance unless either you can edit the Mode class or you work out the precise type of object.
    So the only option left to you is to create a map (lookup) between objects of type Mode and objects of type SpecialModeCommon.

    ________________________________________________________________

    Another option is a seriously DIRTY HACK.
    reorder the multiple inheritance to put SpecialModeCommon first
    making a dummy class to cast to that inherits from both SpecialModeCommon and Mode.

    I just know I'm going to get flamed for even suggesting that one.
    I certainly would hate to know that any software I use is based on it.
    Last edited by couling; January 14th, 2009 at 10:37 AM. Reason: Added Reference
    Signature
    Please use: [ code ][/ code ] tags and reasonably correct tabbing. They really help us read your code
    End Signature

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

    Re: Multiple Inheritance and Casting

    Quote Originally Posted by Eggman002 View Post
    The problem with that solution (unless I am missing something) is that I then have to do the following:
    ....
    Not at all. You implement the method on the class, and it redirects, you NEVER perform a cast.

    I suppose it doesn't matter since that is essentially what I wound up having to do in order to get it to work, but it seems wasteful.
    Writing "correct" programs is not about the effort that you have to put in. It is about properly expressing the actual intended relationships.

    If one has 100 classes that do not conceptually fully support the IS-A (eg 1 out of 1000 use cases would be incorrect), then the appropriate (IMPO) approach is to put the functionallity in a common class and aggregate it, putting "forwarding" methods in each of the individual classes (or possibly at some lower level VALID common IS-A point)

    To avoid duplication, and maintenance issues, I will (note: .inh is an extension I use to indicate a file that is meant to be included at some point in other .h file, but never to be directly included in a .cpp)
    Code:
    //commn.inh
    {
       void F1() {m_Common.F1(); 
       void F2() {m_Common.F2(); 
       void F3() {m_Common.F3(); 
    }
    
    //sample_class.h
    //that needs to support the common behaviour but does not represent IS-A
    
    class SomeClass
     {
    public:
         void MyCursomMethos();
    #include "common.inh"
    }
    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

Page 1 of 3 123 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