-
January 13th, 2009, 04:15 PM
#1
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
-
January 13th, 2009, 05:17 PM
#2
Re: Multiple Inheritance and Casting
Originally Posted by Eggman002
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.
-
January 13th, 2009, 05:20 PM
#3
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
-
January 13th, 2009, 05:39 PM
#4
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
-
January 14th, 2009, 06:12 AM
#5
Re: Multiple Inheritance and Casting
Originally Posted by _uj
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
-
January 14th, 2009, 06:39 AM
#6
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
-
January 14th, 2009, 07:08 AM
#7
Re: Multiple Inheritance and Casting
Originally Posted by Eggman002
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#).
-
January 14th, 2009, 07:11 AM
#8
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.
-
January 14th, 2009, 08:03 AM
#9
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
-
January 14th, 2009, 08:30 AM
#10
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
-
January 14th, 2009, 08:37 AM
#11
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
-
January 14th, 2009, 09:26 AM
#12
Re: Multiple Inheritance and Casting
All comments in this post refer to public inheritance...
Originally Posted by Eggman002
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
-
January 14th, 2009, 10:14 AM
#13
Re: Multiple Inheritance and Casting
Originally Posted by TheCPUWizard
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
-
January 14th, 2009, 10:20 AM
#14
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
-
January 14th, 2009, 10:43 AM
#15
Re: Multiple Inheritance and Casting
Originally Posted by Eggman002
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
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|