View Full Version : Inheriting
ClarustheDogCow
2002.06.25, 06:20 PM
I have a dillema and was wondering of the best C++ solution.
I need to set a child to a parent in multiple situations with multiple children, preferably without a large redundancy in code.
For example,
=SNIP=
struct Parent
{
int married;
int dead;
int cool;
};
struct Child : Parent
{
int age;
};
void sample(Parent *parent) {}
void main(void)
{
Child child;
Parent parent;
sample(&parent);
sample(&child);
parent.married=1;
parent.dead=0;
parent.cool=1;
child=parent;
child.age=2;
}
=SNIP=
Why doesn't child=parent work if sample() works? Is there a deeper reason to this? Is there a way I could make one operator that works for all inheriters of Parent?
OneSadCookie
2002.06.25, 06:54 PM
child = parent doesn't work because although every child is a parent, not every parent is a child.
In this example, child has an age field which parent doesn't. What would that be set to if the assignment worked?
You can always go up the inheritance hierarchy from subclass to superclass, never back down again.
GoodDoug
2002.06.25, 07:01 PM
child=parent will simply make the parent pointer point to child. Now, because parent was explicitly created as a Parent object, it has no storage for the age member of the Child class. What you will want to do is override your = operator to perform an explicit copy of member variables over. Or, you can override the cast operator (from Parent to Child what's called a "promotion cast" by some) to return a newly allocated child object that has storage for the age member varaible. These can become a memory management nightmare if not handled correctly.
One of the things people rag on C++ about is the amount of implicit conversion it will do for you. In this case it is trying to do an implicit conversion and getting tripped up (as it rightly should) You need to either override the = operator or the cast operator in this case. I would be very wary of overriding the cast operator, as it is quite likely that you would be doing it for the wrong reasons. It would also be likely to hide some bugs underneath. In general, promotion style casts are very bad mojo, and if you feel you need to use them, then there might be something wrong in the higher level design. Overriding the = operator is probably your best bet.
Good Luck
ClarustheDogCow
2002.06.26, 08:19 AM
Doing something like this will work with any inheriter of Parent:
void ParentCopy(const Parent *parent, Parent *child)
{
child->married=parent->married;
child->dead=parent->dead;
child->cool=parent->cool;
}
I figure this is because the first bytes are the same for child and parent in memory. I could probably even do a memcpy. The best operator I could get out of this that works is:
Child &Child::operator=(const Parent &parent)
{
ParentCopy(&parent,this);
return *this;
}
I tried to make a Parent*...operator=...Parent* but it doesn't get called. I don't think that the above operator overloading takes much more overhead than just calling ParentCopy, so I think I'll work around a similar solution.
kainsin
2002.06.26, 10:24 AM
Because of inheritance it's definitely a good idea to make sure that the Parent class knows nothing about the Child class. As was mentioned before, I'd overload the = operator to perform this task.
in Child class definition:
public:
Child & operator=( const Parent & rightValue );
friend Parent & operator=( Parent & leftValue, const Child & rightValue );
in Child class implementations:
Child & Child::operator=( const Parent & rightValue ) {
this->married = rightValue.married;
this->dead = rightValue.dead;
this->cool = rightValue.cool;
return ( *this );
}
Parent & operator=( Parent & leftValue, const Child & rightValue ) {
leftValue.married = rightValue.married;
leftValue.dead = rightValue.dead;
leftValue.cool = rightValue.cool;
return leftValue;
}
That should take care of copying between a child and a parent. You may want to override the assignment operator on most classes you create. Especially if you use it as a short-hand method of copying and also if your classes use pointersto dynamically allocated data that might need to be deep coppied.
hokan
2002.06.26, 04:46 PM
Naturally I don't know how this will be used, but to me this does looks like a bad design decision.
Parent can be a Child, Child can be a Parent - these are two aspects of the same person, it seams to me that it would make more sense to have a Person class:
struct Person
{
int married;
int dead;
int cool;
int age;
};
that contains all the fields used by both Parent and Child.
The Parent and Child class should both inherit from Person to be able to reimplement certain methods (or supply ones that only apply to a person of that aspect).
The parent - child relationship is not a property of the Person class but should rather be modeled by a relationship graph, which can be used to determine if a Person is to be treated as a Child or a Parent.
You could add a father and mother field to Person to model this (a separate graph class could also be used for this):
struct Person
{
int married;
int dead;
int cool;
int age;
Person *father; // set to NULL if unknown
Person *mother; // set to NULL if unknown
};
Examining the father and mother (parent) edges in the relationship graph allows you to find all kinds of relationships (parents, brothers, grandparents, grandchildren ... of a certain person).
kainsin
2002.06.27, 08:36 AM
Hmmm...that would work if the question was dealing with actually implementing people as classes. Something tells me that the "Parent-Child" question was being used as an example to better understand C++ inheritance.
ClarustheDogCow
2002.06.27, 10:34 AM
It is an example to play around with inheritance.
I was making a little space invader type game, but the enimies have different types. I was going to make a "player" parent with the coordinates and speed, health etc. And have every kind of enimy space ship inherit from that. That way I could have different commands special to each class in the different ship structs. I could call xwing.draw() or tiefighter.draw(), for example, and they would draw their own type of spaceships.
Instead of comparing a ton of different types for collision detection, I would "borrow" the parent class and use that to compare. I guess I really should be making a kind of sprite class above them.
This discussion has helped me understand inheritance a lot. Thanks for your replies=]
swcrissman
2002.06.27, 11:43 PM
I think Hokan's general idea is still applicable to your situation, Clarus, if not exactly by name.
The thing to remember is that as you move down the inheritance chain, things should get more specific, and as you move up it, more generalized. If two items are equally specific, and neither really is the other, then inheritance is probably the wrong route.
Here's an easy test to see if you should make a class a subclass: can you state that in general, the subclass IS A superclass? In this case, you can't really say that a player is an enemy, or an enemy is a player. Instead, thinking in more broad terms, you could for example create a SpaceShip class, and both enemy and player could inherit from that class. Reviewing, you can see that you can easily state that a player is a SpaceShip, while an enemy is a SpaceShip as well, so it seems to make sense for your given situation.
I hope that helps you out. I think more questions like these are really good ways to open discussions on general coding theory, which is something that is hard to get. When you start programming, its easy to find answers to syntax problems, or function calls, but actual program architecture is a bit more elusive. Don't hesitate to ask more about these kinds of things, as I think everyone benefits from them, to some extent.
Spencer
vBulletin® v3.8.4, Copyright ©2000-2010, Jelsoft Enterprises Ltd.