Jump to content
  • Advertisement
Sign in to follow this  
maximAL

decorator pattern & C++...

This topic is 4872 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i just tried to implement the decorator pattern and i'm not sure if i was struck down by a design flaw of C++ again. so, for the decorator pattern you need an interface class your decorator can inherit from. thats because you only want to inherit the interface to "overwrite" certain functions, but you have no use for the implementation (which would be unused overhead). take a simple class hierarchy as in the GoF-book. you got sth. like this: Interface->DerivedImpA->DerivedImpB where the Interface is an abstract class that only provides the interface for all the derived class (implementations). here you could easily implement a decorator by inheriting from Interface. but it could only use Interface'es interface. now the problem: how to implement decorators for a whole hierarchy and not just one base class? maybe i want extended decorators for the derived classes, too? but then i need their interface! how to get it? i won't inherit from them, since i don't want the implementation (memory overhead!). my first idea was to build a whole hierarchy of (abstract) interfaces first, like: Interface->DerivedInterfaceA->DerivedInterfaceB and then do implementations for them: DerivedInterfaceA->DerivedImpA DerivedInterfaceB->DerivedImpB here the problems start: when always inheriting from the interface, DerivedImpB doesn't inherit from DerivedImpA - thats probably not what you want. only - ugly - solution: inherit always from the interface AND the implemetation class (for DerivedImpB from DerivedInteraceB and DerivedImpA). but that sucks too, because 1. you have pretty much overhead for every class (eg. 2 vtable indexes for 2 classes - growing exponential with the hierarchy!) and you have to re-implement every function, because of the pure virtual function of the interface class AND the ambiguity between the interface and the implemention. even if you want to inherit from the implementation, you have to re-implement the functions - to manually call the implemention's function ( Do(){Imp::Do();}; ) is C++ seriously lacking some features here? maybe being able to inherit only the interface from a class would be great here... after all, it's not the first time for me that an intuitively good idea was cracked by implemenation difficulties with C++... is there actually a solution to this? or is it just impossible to design OO software using advanced techniques and i should be happy with "C with classes"? (btw, i you don't know what the decorator pattern (or a pattern at all) is but want to flame me - stfu.)

Share this post


Link to post
Share on other sites
Advertisement
Hi,

I'm sorry but I don't seem to get your problem.

interface
/ DIA DIC
/
DIB

and you have implementaions for them !?

ImplDIA public DIA
ImplDIB public DIB
ImplDIC public DIC

and know comes the point where I don't see your problem.
Sorry but I really would like to help.

(I do know patterns and c++ well)

Share this post


Link to post
Share on other sites
Sounds a bit like "I've got a hammer and a nail that I want to put in this wall, but I keep hitting my fingers. The hammer must have a problem. Could it be that hammers are not suited for hammering nails into walls ?" :D

I also don't quite understand where the problem lies. You've got one of the most powerful languages out there, one of the few languages, in fact, which have the concepts of multiple inheritance and virtual inheritance, and it is absolutely possible to implement any design pattern, including the decorator, in C++.

-Markus-

Share this post


Link to post
Share on other sites
yes, it's hard to explain, i know...
of course, knowing the decorator pattern is essential, plus you might only see the problem when actually trying to implement it.
i'll try to give a simple game-related example.

//our interface for GameObjects
//every GameCharacter should have GetHealth (etc.)
struct iGameCharacter
{
virtual int GetHealth(void)=0;
};

//now implement one
//notice the new method!
class cMonster : public iGameCharacter
{
public:
virtual int GetHealth(void){/*funky stuff*/};
virtual void Attack(iGameCharacter *Victim){/*let's kill it...*/};
};

//now our Decorator
//remember, decorating works by inherting the interface
//(so you can use it like the original object)
//and wrapping up function calls to the actual objects
class GameCharacterDeco : public iGameCharacter
{
private:
//we need the pointer to access the actual object
//we only inherit the interface!
iGameCharacter *Character;
public:
GameCharacterDeco(iGameCharacter *character):Character(character){};
//and now decorate a function
virtual int GetHealth(void)
{
/*do extra stuff*/
return Character->GetHealth();
}
};




this works great for the interface iGameCharacter provides.
but stop: i'd also like to decorate the new functions of cMonster! i can't decorate Attack() with my GameCharacterDeco!
what now? no, i won't derive from cMonster. this is an implementation. it might have tons of data in it and as you might have noticed, the decorator accesses the actual object through a pointer and does nothing with the inherited implementation (and thats necessary because you can use several decoratos at once recursively via the pointer).

my idea was to have a complete interface hierarchy, so i'd also have iMonster interface (derived from iGameCharacter).
this interface would allow me to write a decorator.
but the problem arises when implementing iMonster via cMonster.
cMonster has to inherit the interface of iMonster.
but building a whole hierarchy, you might also have a cEndBoss class that needs to inherit it's interface from iEndBoss. but it might also need to inherit the implementation of cMonster.
well, there we are again. inheriting from an implementation AND an interface. problems arise...

[Edited by - maximAL on June 1, 2005 8:43:35 AM]

Share this post


Link to post
Share on other sites
If I understand what you were after you will end up with something like this:


// iMonster
// / \
// / \
// / \
// cMonster iEndBoss
// \ /
// \ /
// \ /
// cEndBoss




This is icky and ambiguous. So just have iMonster as a virtual base class:



struct iMonster: public iGameCharacter {
virtual void Attack(iGameCharacter *Victim) = 0;
};

//new cMonster using iMonster interface
class cMonster: virtual public iMonster {
public:
virtual int GetHealth() {/* ... */}
virtual void Attack(iGameCharacter *Victim) {/* ... */}
};

// interface. even if we are bigger and scarier,
// we are still a monster
struct iEndBoss: virtual public iMonster {
virtual void ExplainEvilPlan() = 0;
};

// implementation of EndBoss
class cEndBoss: public iEndBoss, public cMonster {
public:
virtual void Attack(iGameCharacter *Victim) { /* bossier attack here */}
virtual void ExplainEvilPlan() {/* ... */}
};





Since iMonster is an interface you dont have to worry about remembering to call the iMonster constructor either.

Are there any problems with this? (if you're not familiar with virtual inheritance check out this link).

Share this post


Link to post
Share on other sites
now thats great! hmm, i really didn't think of virtual inheritance, hadn't seen seen this for quite a while.
it seems to solve my problem. but it also has some issues, so i'm not sure if i'll do it this way.
but anyway, thanks rollo!

Share this post


Link to post
Share on other sites
Virtual inheritance? I think not.

If the logic that you want to decorate a Game Character with makes sense for a monster, than maybe you need to reevaluate what a monster is. In particular, does it make sense to say a "monster is a game character?" In that case, you would have a hierarchy like this...


Base <- Child

IGameChar <- IMonster
IGameChar <- GameChar
IMonster <- Monster
IMonster <- Boss


GameCharDecorator would then contain a pointer to an IGameChar, and can augment monsters, bosses, and game characters. The common behavior from bosses and monsters would be pushed into IMonster. If you have specific behavior you want to decorate a monster with, you would implement the IMonster interface as a MonsterDecorator, and then pass that to your CharDecorator as an IGameChar. Now we have composite decorators -- we win.

Also, as a side note, prepending "C" to everything that isn't an interface to show it is Concrete or a Class is redundent. Don't do it.

Share this post


Link to post
Share on other sites
Quote:
Original post by ClashIf the logic that you want to decorate a Game Character with makes sense for a monster, than maybe you need to reevaluate what a monster is. In particular, does it make sense to say a "monster is a game character?" In that case, you would have a hierarchy like this...
...
Also, as a side note, prepending "C" to everything that isn't an interface to show it is Concrete or a Class is redundent. Don't do it.

all the above code was a simplified example to illustrate the problem.

Share this post


Link to post
Share on other sites
I would suggest at least considering not using hierarchies for game objects. In my experience, they never do exactly what you want, particularly when requirements and design change as frequently as they do in game design. Take a look at:

http://gamearchitect.net/Articles/GameObjects1.html

Granted, I am sure this approach has its own set of issues, but it is an interesting direction.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!