Link to home
Start Free TrialLog in
Avatar of sneeuw
sneeuwFlag for Belgium

asked on

Need Advice ... Can I have a class member look like another type to not loose extra memory space

This probably is a stupid question but here goes ...

E.g. (simplified)

Base
 |
Derived1
 |-------------------|--------------|
Derived11         Derived12       Derived13


Derived1 has a member :
Derived1 *DerivedParent ;

And Derived11, 12 and 13 make use of this DerivedParent to get certain data.

I now come to the conclusion that maybe I should have placed a Parent in Base :
Base *Parent
because other classes derived from Base could use the member too + it would make creating a special other class easier too.

To not have to rewrite all the classes that now DerivedParent as a Derived class instead of Base class I was wondering if I could put the member in Base but have it look like all's the same ???

I can have a Parent in Base AND Derived1
and in the Derived constructor write :
Base::Parent = Parent ;

But then I would have two pointers instead of one (I can miss the extra 4 bytes per object)

So I was wondering if it is not possble to have the Parent in Base but some sort of ???don't know??? in Derived1 that doesn't take physical space and looks like a pointer to Derived1. ???

I could also In Derived1 change DerivedParent to a function DerivedParent() (still re-write required but minimal).
But then I would have to dynamic_cast the Base pointer :

Derived1 *DerivedParent()
 {
 return dynamic_cast<DerivedParent*>(Base::Parent) ;
 }

But then I ask myself dynamic_cast is this slow ??
What does it take for code to constantly check with dynamic_cast ??

Hope this all makes sense.
I'm new to OOP but I'm learning !!!


Avatar of nietod
nietod

>>  if I could put the member in Base but have it look like all's the same ???
The real question is how does this additional pointer member affect the interface of the Base class.  If it has no affect ont he interface, then yes, the base class still looks the same If the pointer affects the interface, then the base class has changed, you then need to look more closely at how it has changed to see what effect this has.

For example, is the member A) private or B) protected/public.   If A, then it doesn't affect the interface, if B then it is may be a small change to the interface.  The next question, if B, is does code outside of the base class need to change this data member?  If so this may be an area of problem  You need to consider what code needs to change it and how much trouble it will be to alter the code so that it does change it.

Next consider if there are functiosn that A) obtain and B) set the value of the member.  If A, it is a slight affect on the interface, but that should not matter.  If B, that is a bigger effect.  Again you need to consider if code outisde of the class will need to set this data member.  if so, this could be a problem   Again think about how much trouble it will be to insure that this data member is set correctly

Next consider if there are existing functions outside of the base class, probably virtual functions, but maybe not, that will be affected by this data member.  i.e. will then need to use this data member in their implimentaition?   if so, again you need to consider how hard it will be to make this change.

continues
>> I can have a Parent in Base AND Derived1
>> and in the Derived constructor write :
>> Base::Parent = Parent ;
What about Derived2? and 3?

Do these need this data member?  If not, then it definitely suggests that adding it to Base is a mistake.  

If that is the case, that Base needs it and Derived1 needs it, but not 2 and 3, then consider an alternative.    Leave Base as is. i.e don't add this data member to Base.  Then derive a new class from Base, lets call it Base2.  Add this data member to Base2.  Then derive Derive1 from Base2, so Derive and Base 2 both have this new data member.  but derive Derived2 and Derived3 from Base, not Base1, so these don't have this additional data member.

>> So I was wondering if it is not possble to have the Parent in Base but
>> some sort of ???don't know??? in Derived1 that doesn't take physical
>> space and looks like a pointer to Derived1. ???
No.  But wasted space is probalby the least significant problem for you to consider.  You need to consider if this change leands to illogical interfaces or difficult source code changes.  By illogical interfaces, I mean things like will the Derived2 class have a function that sets this data member, yet it never uses this data meber for anything?  That is messy and can come back to haunt you.

>> But then I ask myself dynamic_cast is this slow ??
>> What does it take for code to constantly check with dynamic_cast ??
Its slow compared to other casts,  In fact MUCH slower,  but still its not really that slow.  You should be able to peroform 1000s of them in a second (probalby 10s of 1000s or 100s of 1000s really).  How often doyou really need to do this cast?  probably not so often that the extra time will matter.
Avatar of sneeuw

ASKER

Hi nietod,

I guess you're right.
Parent shouldn't be really in Base

The problem I face is that Base has several types of decendants each with their own kind of Parent (the Parent types differ).

I was now writing a piece of code and was looking for some way to make it all look the same so that I could use a pointer to Base to work from instead of having to check the type of Object and then decide on the type of parent.

For the same reason I wanted a function and some additional variables in Base so that I could generalise working with the different decendants of Base.
However, this then looks 'stupid' as the function resides in Base but the actual Parent resides in the derived class.
e.g.  
Base::DoSomethingWithParent(void) ;

But in Base then the function would be virtual or do nothing and the actual decendants do the work.

 
>> The problem I face is that Base has several types of
>> decendants each with their own kind of Parent (the
>> Parent types differ).
Sometimes that means that the base class should not contain the pointer and sometimes it does.

For example consider a window object hearachy--I hope you are familar with windows.   Each window has a parent window--except top level windows.  so each window object has a pointer to its parent window object, int op-levle windows the pointer is NULL.   For most windows the parent window can be of any class type, so the parent window object could be any type derived from the base window class (WindowBase, say).  But for some windows the parent has to be of a particular class type.  For example, a MDI Child window has to have a parent that is a MDI Client window.  But not every window has a parent that is a MDI client window, so the parent window pointer stored in the base class, must point toa base class window object, not a MDI client window object.   This means that the MDIi child window object will at times have to cast its parent window object from a base class to a MDI client window.   But that only has to be done when features specific to the MDI client are needed.    In this case It would nto make sense to remove the parent pointer from the base class, as I suggested above, because virtually every single window object needs this pointer and most of the times it is used, it is used by the base class.  i.e. when a child window is created, moved, sized, painted, and 100s fo other fucntions  this pointer is needed.  

>> The problem I face is that Base has several types of decendants
>> each with their own kind of Parent (the Parent types differ).
Then the question you need to ask yourself is how much is common to all the classes regarding this pointer?   For example, are there lots of operations performed by the base class that will need this pointer.  if so, you might want to leave it in the base class and downcast.  On the other hand, if the use fo this pointer is pretty specific to the derived classes, and differes from class to class, then pt it in the derived class.   Finally there is a 3rd option.  Store the pointer in the derived class.  This allows the derived class to store it as the exact type needed (like in my example, it could be a pointer to a MDI client window obkect for some classes).   This also allows the derived classes to informace retraints n the pointer, alllowing it to be set in cenrtain ways etc.    Then if the base class needs the pointer for common operations, it cann call a virtual procedure that returns the pointer (typed as a pointer to some base class, if needed)   Each of the derived classes have to impliment this procedure to return the pointer they store.   This can solve your issues with

Base::DoSomethingWithParent(void)

The derived classes can store pointers to parents of non-BAse types, as is appropriate for them.  For their operations, they are able to use a pointer of the derived class type, as appropriate for them and without casting.   But for "common" operations, the base class can get a hold of the pointer to do work tht is common to all classes.
Avatar of sneeuw

ASKER

> Finally there is a 3rd option ...

Yes, this is the idea I'm playing with now.
So this wouldn't be regarded as a 'bad' way of making use of OOP ?

I mean ... the first example (MDI vs. Base) makes a lot of sense but then I would have to change a lot and do A LOT of casting in the derived classes.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial