P
Patchwork
Hi Everyone,
I have a design related question (in C++) that I am hoping someone can help
me with. It is related to my previous post but since it was pointed out that
I was more or less asking the wrong questions about the wrong 'topic'
(polymorphism) I have posted this new question. Please don't see this as a
spurious attempt to repost
As mentioned previously, there is a very real problem I am trying to solve,
but I have reduced it to as simple a concept as I can.
Here are my requirements:
1) There is a class CFood which implements a generic food class and will be
subclassed. Each foodtype will have its own properties, etc making good use
of polymorphism where appropriate (honest).
2) CFood objects will be stored, generically, in lists. For example, a class
CPantry may contain a std::list of CFood pointers.
3) There is a class CLifeform which will also be subclassed (e.g. CMonster
or CHumanoid). Food may be taken from one of the lists/collections and
offered to a lifeform. Each CLifeform-based class may process or eat
CFood-derived objects differently. For example, CHumanoid-based classes may
eat CCookie objects whereas CMonster-based classes may eat other lifeforms.
4) Other classes (not CLifeform-drived) may also eat/handle CFood objects.
My current 'solution' looks like this:
/////////////////////////////////////////////////////
// Monster Munch
#include "stdafx.h"
#include <list>
class CFood
{
public:
CFood() {}
virtual ~CFood() {}
};
class CFoodCookie : public CFood
{
public:
CFoodCookie() {}
virtual ~CFoodCookie() {}
// Cookie properties...
};
class CFoodHorse : public CFood
{
public:
CFoodHorse() {}
virtual ~CFoodHorse() {}
// Horse properties...
};
class CLifeform
{
public:
CLifeform() {}
virtual ~CLifeform() {}
public:
virtual bool Feed(CFood* pFood) {printf("\nI don't know what this is!");
return false;}
virtual bool Feed(CFoodCookie* pFood) {printf("\nI don't eat cookies!");
return false;}
virtual bool Feed(CFoodHorse* pFood) {printf("\nI don't eat horses!");
return false;}
};
class CHumanoid : public CLifeform
{
public:
CHumanoid() {}
virtual ~CHumanoid() {}
virtual bool Feed(CFoodCookie* pCookie) {delete pCookie; printf("\nYummy! A
cookie!"); return true;}
};
class CMonster : public CLifeform
{
public:
CMonster() {}
virtual ~CMonster() {}
virtual bool Feed(CFoodHorse* pHorse) {delete pHorse; printf("\nI was so
hungry, I ate a horse!"); return true;}
};
class CPantry
{
public:
CPantry() {}
~CPantry() {}
void AddFood(CFood* pFood)
{
m_Stock.push_back(pFood);
}
void Feed(CLifeform& Lifeform)
{
while (m_Stock.size())
{
// Get the food...
CFood* pFood = m_Stock.front();
m_Stock.pop_front();
if (!Lifeform.Feed(pFood))
{
// Throw the food away
delete pFood;
}
}
}
private:
std::list<CFood*> m_Stock;
};
int main()
{
CPantry ThePantry;
// Let's see what we have:
// Two cookies...
ThePantry.AddFood(new CFoodCookie());
ThePantry.AddFood(new CFoodCookie());
// Goodness knows what this is...
ThePantry.AddFood(new CFood());
// And this, apparently...
ThePantry.AddFood(new CFoodHorse());
// Feed the guest...
CMonster ScaryDude;
ThePantry.Feed(ScaryDude);
getchar();
return 0;
}
/////////////////////////////////////////////////////
There are pros and cons to this solution, as I see it. These are...
Pros:
1. CLifeform derived classes need only override the 'handlers' for the foods
they wish to eat.
2. Each Feed() method has a pointer to the specific object type to be
handled appropriately.
Cons:
1. It doesn't work! I know exactly why it doesn't work, CFood* is always
passed to the CLifeform class, so the lifeform never knows what it is being
fed. The design change (or redesign) must allow pointers to specific
CFood-derived classes to be passed around.
2. CLifeform has to know (beforehand) of all food types that could ever be
handled by subclasses...however, I also see this as desirable...
Regarding Con1, I can conceive of one way around this. Perhaps CFood could
be given a virtual method such as:
bool CFood::FeedLifeform(CLifeform& Lifeform)
{
Lifeform.Feed(this);
}
However, each CFood-derived object would need to override this, but
implemented with exactly the same code! First, CFood classes will be added
frequently, so I wish to minimise the code involved in implementing a
subclass. Second, this would require that CFood knew explicitly that it may
be used to feed CLifeform classes. I don't want the class to know that and,
as stated, CFood classes may be handled by non-CLifeform-derived classes
also - more CFood overhead.
I also realise that each CLifeform-derived class could examine a generic
CFood pointer and determine what to do with the food according to its type.
However, I really like the idea of CLifeform subclasses just overriding the
food handlers they are interested in.
Given the requirements and preferences, can anyone suggest anything
fruitful?
Many many thanks,
Lucy x
I have a design related question (in C++) that I am hoping someone can help
me with. It is related to my previous post but since it was pointed out that
I was more or less asking the wrong questions about the wrong 'topic'
(polymorphism) I have posted this new question. Please don't see this as a
spurious attempt to repost
As mentioned previously, there is a very real problem I am trying to solve,
but I have reduced it to as simple a concept as I can.
Here are my requirements:
1) There is a class CFood which implements a generic food class and will be
subclassed. Each foodtype will have its own properties, etc making good use
of polymorphism where appropriate (honest).
2) CFood objects will be stored, generically, in lists. For example, a class
CPantry may contain a std::list of CFood pointers.
3) There is a class CLifeform which will also be subclassed (e.g. CMonster
or CHumanoid). Food may be taken from one of the lists/collections and
offered to a lifeform. Each CLifeform-based class may process or eat
CFood-derived objects differently. For example, CHumanoid-based classes may
eat CCookie objects whereas CMonster-based classes may eat other lifeforms.
4) Other classes (not CLifeform-drived) may also eat/handle CFood objects.
My current 'solution' looks like this:
/////////////////////////////////////////////////////
// Monster Munch
#include "stdafx.h"
#include <list>
class CFood
{
public:
CFood() {}
virtual ~CFood() {}
};
class CFoodCookie : public CFood
{
public:
CFoodCookie() {}
virtual ~CFoodCookie() {}
// Cookie properties...
};
class CFoodHorse : public CFood
{
public:
CFoodHorse() {}
virtual ~CFoodHorse() {}
// Horse properties...
};
class CLifeform
{
public:
CLifeform() {}
virtual ~CLifeform() {}
public:
virtual bool Feed(CFood* pFood) {printf("\nI don't know what this is!");
return false;}
virtual bool Feed(CFoodCookie* pFood) {printf("\nI don't eat cookies!");
return false;}
virtual bool Feed(CFoodHorse* pFood) {printf("\nI don't eat horses!");
return false;}
};
class CHumanoid : public CLifeform
{
public:
CHumanoid() {}
virtual ~CHumanoid() {}
virtual bool Feed(CFoodCookie* pCookie) {delete pCookie; printf("\nYummy! A
cookie!"); return true;}
};
class CMonster : public CLifeform
{
public:
CMonster() {}
virtual ~CMonster() {}
virtual bool Feed(CFoodHorse* pHorse) {delete pHorse; printf("\nI was so
hungry, I ate a horse!"); return true;}
};
class CPantry
{
public:
CPantry() {}
~CPantry() {}
void AddFood(CFood* pFood)
{
m_Stock.push_back(pFood);
}
void Feed(CLifeform& Lifeform)
{
while (m_Stock.size())
{
// Get the food...
CFood* pFood = m_Stock.front();
m_Stock.pop_front();
if (!Lifeform.Feed(pFood))
{
// Throw the food away
delete pFood;
}
}
}
private:
std::list<CFood*> m_Stock;
};
int main()
{
CPantry ThePantry;
// Let's see what we have:
// Two cookies...
ThePantry.AddFood(new CFoodCookie());
ThePantry.AddFood(new CFoodCookie());
// Goodness knows what this is...
ThePantry.AddFood(new CFood());
// And this, apparently...
ThePantry.AddFood(new CFoodHorse());
// Feed the guest...
CMonster ScaryDude;
ThePantry.Feed(ScaryDude);
getchar();
return 0;
}
/////////////////////////////////////////////////////
There are pros and cons to this solution, as I see it. These are...
Pros:
1. CLifeform derived classes need only override the 'handlers' for the foods
they wish to eat.
2. Each Feed() method has a pointer to the specific object type to be
handled appropriately.
Cons:
1. It doesn't work! I know exactly why it doesn't work, CFood* is always
passed to the CLifeform class, so the lifeform never knows what it is being
fed. The design change (or redesign) must allow pointers to specific
CFood-derived classes to be passed around.
2. CLifeform has to know (beforehand) of all food types that could ever be
handled by subclasses...however, I also see this as desirable...
Regarding Con1, I can conceive of one way around this. Perhaps CFood could
be given a virtual method such as:
bool CFood::FeedLifeform(CLifeform& Lifeform)
{
Lifeform.Feed(this);
}
However, each CFood-derived object would need to override this, but
implemented with exactly the same code! First, CFood classes will be added
frequently, so I wish to minimise the code involved in implementing a
subclass. Second, this would require that CFood knew explicitly that it may
be used to feed CLifeform classes. I don't want the class to know that and,
as stated, CFood classes may be handled by non-CLifeform-derived classes
also - more CFood overhead.
I also realise that each CLifeform-derived class could examine a generic
CFood pointer and determine what to do with the food according to its type.
However, I really like the idea of CLifeform subclasses just overriding the
food handlers they are interested in.
Given the requirements and preferences, can anyone suggest anything
fruitful?
Many many thanks,
Lucy x