• Advertisement
Sign in to follow this  

decorator pattern & C++...

This topic is 4605 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
Quote:
Original post by BrianLhttp://gamearchitect.net/Articles/GameObjects1.html

hmm, too bad the author only makes some vague statements about flat hierarchies and components (and the interesting links are dead), so i don't really have an idea what his design looks like.

back to bringing up more ideas: policies
instead of extending interfaces by inheritance one could introduce new classes only containing the extended interface.
the implementations as well as the decorators could be pieced together by inherting from several interfaces.

example:
interfaces:
iGameCharacter - provide basic functionality for all gamecharacters
iMonster - only provide extended functionality for monsters
iEndBoss - ...

implementation:
iGameCharacter<-GameCharacter
iMonster,GameCharacter<-Monster
iEndBoss,Monster<-EndBoss

decorators:
iGameCharacter,iMonster<-GC_MonDeco - decorate the gamecharacter and monster inteface
iEndBoss<-EBDeco - decorate the EndBoss interface only

well, seems pretty clean so far. multiple inheritance but no diamond of death. extremely extendable and flexible.

but, of course, those bitchy vtable data induces some bloat, namely 4 bytes per intefaces.
sure, it won't really matter for the most time. but i always ask myself what if.... what if the variety of gamecharacters boosts up and you got plenty, real plenty of instances and your little homebrew game looks and plays like '95 and it's unreasonable to need so much memory...? (yes, thats unlikely to happen with gamecharacters, but you can think of sth. else i guess).


@Clash, btw. i had no intention to sound rude, you made a reasonable point.

Share this post


Link to post
Share on other sites
Quote:
hmm, too bad the author only makes some vague statements about flat hierarchies and components (and the interesting links are dead), so i don't really have an idea what his design looks like.
I didn't bring this up because we were talking about decorators, but for building game objects you should prefer to use composition instead of inheritance. And generally speaking, if composition can solve the problem it should be prefered over inheritance. Anywho, the idea is basically this:

The bits and pieces of functionality you want to give to different game entities gets packaged up into reusable components. Each game entity, when created, has any number of these components created and attached to it. The components, of a single entity, can communicate with eachother using broadcasted messages. Components can then be configured to trigger specific behavior when a specific message is received.

There is a really good article on this in the new Game Programming Gems.

Quote:
decorators:
iGameCharacter,iMonster<-GC_MonDeco - decorate the gamecharacter and monster inteface
iEndBoss<-EBDeco - decorate the EndBoss interface only
If IMonster extends IGameCharacter, then there is no need to have a decorator explicitly for both. If the behavior that is being added can be done with an IGameCharacter, then the decorator shouldn't have any knowledge of an IMonster. If you added a new game character, and wanted to decorate it, it wouldn't make much sense based on the name... even though the logic would make sense.

Quote:
...those bitchy vtable data induces some bloat, namely 4 bytes per intefaces.
I'm pretty sure that each concrete type only has 1 vtable pointer per instance. The more virtual functions you have, the larger the vtable will be, but you don't have multiple vtable pointers. Unless maybe you use virtual inheritance? I never do.. so I dunno.

Quote:
@Clash, btw. i had no intention to sound rude, you made a reasonable point.
No worries. We'are all friends here :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Clash
Quote:
...those bitchy vtable data induces some bloat, namely 4 bytes per intefaces.
I'm pretty sure that each concrete type only has 1 vtable pointer per instance. The more virtual functions you have, the larger the vtable will be, but you don't have multiple vtable pointers. Unless maybe you use virtual inheritance? I never do.. so I dunno.


class Base1{private: virtual void DoBase1()=0;};
class Base2{private: virtual void DoBase2()=0;};
class Base3{private: virtual void DoBase3()=0;};
class Derived:public Base1,public Base2,public Base3
{
virtual void DoBase1(){};
virtual void DoBase2(){};
virtual void DoBase3(){};
};

sizeof(Derived)==12; [attention]
every inherited class has its own vtable pointer obviously...

Share this post


Link to post
Share on other sites
Interesting. This behavior seems to be the case on both the .NET2003 and Intel 8.0 compilers. It looks like you only get extra vtable pointers when you do multiple inheritance though (as opposed to multiple single-inheritances). I wonder if this is standard C++ behavior or implementation dependent.

Share this post


Link to post
Share on other sites
Quote:
Original post by Clash
Interesting. This behavior seems to be the case on both the .NET2003 and Intel 8.0 compilers. It looks like you only get extra vtable pointers when you do multiple inheritance though (as opposed to multiple single-inheritances). I wonder if this is standard C++ behavior or implementation dependent.

since my mingw does this too, i guess it is standard.

Share this post


Link to post
Share on other sites
Implementation dependant, with a very similar implementation on all platforms.
You should have a vtable pointer if you have any virtual member functions. I haven't dug into the implementation details of virtual inheritence, but suspect it'd be another table pointer (vitable?) per instance.

Share this post


Link to post
Share on other sites
Most implementations favor performance over saving memory. So to implement multiple inheritance you either need (1) a vtable pointer for each inherited class or (2) a single pointer to a table of vtable pointers that point to the vtables of each inherited class. The second approach saves you memory as each object needs only one "meta"-pointer, but it requires two pointer dereferences for every method call at runtime, as opposed to one dereference (following a simple offset calculation) in the first approach.

Share this post


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

  • Advertisement