decorator pattern & C++...

Started by
15 comments, last by Malone1234 18 years, 10 months ago
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.
------------------------------------------------------------Jawohl, Herr Oberst!
Advertisement
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 :)
- Jason Citron- Programmer, Stormfront Studios- www.stormfront.com
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...
------------------------------------------------------------Jawohl, Herr Oberst!
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.
- Jason Citron- Programmer, Stormfront Studios- www.stormfront.com
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.
------------------------------------------------------------Jawohl, Herr Oberst!
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.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
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.

This topic is closed to new replies.

Advertisement