A problem regarding polymorphism C++

Started by
6 comments, last by ChaosEngine 19 years, 1 month ago
I am restructuring the classes in my game demo to accomodate a scene hierachial approach(vs the brute forces methos i had in place). Basically my game is just a whole lot of balls bouncing off static objects and each other with a player trying to avoid them and complete some tasks. So what I have is about 7 different object types(ie. ball, box, cylinder etc..) that i want to derive from a common Object class. The Object class members tell the object what node(i am using an OcTree) the object is currently in, what is the next and previous Object in its cell and the Type of the object. I have implemented this but my problem is that when i am traversing the OcTree for collisions and i find that 2 objects are in need of closer analysis i need to call functions that accept arguments of the children types. For example, i find 2 Objects within a node both have Object->Type= TYPE_BALL so i now need to call a function: pPhysicsEngine->CheckBallBallCollision(Ball* pBall1, Ball* pBall2). But this will not accept arguments of type Object*. I am looking for a way around this...? Thanks for your time and effort. ;p
Advertisement
Since you already seem to have a local RTTI system in place (type == BALL). Why not use it in the collision detection function?


for instance:
PhysicsEngine::CheckCollision(obj* a, obj* b){   if(a->type == BALL   {       if(b->type == BALL         PhysicsEngine::CheckBallBallCollision((ball*)a, (ball*)b);       if(b->type == BOX         PhysicsEngine::CheckBallBoxCollision((ball*)a, (box*)b);   }   if(b->type == BALL       etc....}


Im not sure this was what you were asking for tough.
Shields up! Rrrrred alert!
I maybe wrong but by the sound of things you want to check collision between 2 objects of type *object* but dynamically bind the most appropriate function of the objects real type in question.

If thats the case then you need run-time multiple dispatch on type, C++ only supports single run-time dispatch on type natively so either use a library that implements multi-methods or you could apply the visitor design pattern or re-think your design a little, the loki library provides a generic multi-methods & visitor package you can use.
Peter_b you make it sound too easy ;p

I am such a dufus for forgetting it is possible to typecast the pointer types...thats all the answer i needed! Thanks m8 ;p

snk_kid you are way over my head but thanks for the reply. I wish i could understand that... ;(
Quote:Original post by bobbinus
Peter_b you make it sound too easy ;p

I am such a dufus for forgetting it is possible to typecast the pointer types...thats all the answer i needed! Thanks m8 ;p

snk_kid you are way over my head but thanks for the reply. I wish i could understand that... ;(


The method that Peter_b has shown is the brute force method (besides using C-style casts which is not a good idea use C++ family of cast operators in particular dynamic_cast), its highly error-prone, code becomes fragile and is not very extendable, if i remember correctly for each new type you add the amount of casting/type switching code added is exponential. This is what multi-methods and visitor design pattern overcome nasty type switching in particular.
To be fair, one of the loki methods (StaticDispatcher) is just a brute-force dispatcher, albeit 'more c++'. MC++D does note that this has good compile- and run-time safety, good speed for few classes and no changes necessary to your classes, at the cost of a large amount of dependency added. I'm using it in my (simple) application at the moment, primarily because it removes the hassle of updating all those if-else clauses.

To the OP : it's worth having a look at loki's multimethods just to get a handle on what code it removes. A snippet from my own source:

#pragma once#include <multimethods.h>#include "boundtype.h"#include "boundtypecircle.h"#include "boundtypestaticline.h"#include "boundtypedynamicline.h"#include "boundtypenobound.h"class CollisionExecutor{public:	bool Fire(BoundTypeCircle&,      BoundTypeCircle&);	bool Fire(BoundTypeCircle&,      BoundTypeStaticLine&);	bool Fire(BoundTypeCircle&,      BoundTypeDynamicLine&);	bool Fire(BoundTypeCircle&,      BoundTypeNoBound&);	bool Fire(BoundTypeStaticLine&,  BoundTypeStaticLine&);	bool Fire(BoundTypeStaticLine&,  BoundTypeDynamicLine&);	bool Fire(BoundTypeStaticLine&,  BoundTypeNoBound&);	bool Fire(BoundTypeDynamicLine&, BoundTypeDynamicLine&);	bool Fire(BoundTypeDynamicLine&, BoundTypeNoBound&);	bool Fire(BoundTypeNoBound&,     BoundTypeNoBound&);	bool OnError(BoundType&, BoundType&);};typedef Loki::StaticDispatcher<	CollisionExecutor,	BoundType,	TYPELIST_4(BoundTypeCircle, BoundTypeStaticLine, BoundTypeDynamicLine, BoundTypeNoBound),	true,	BoundType,	TYPELIST_4(BoundTypeCircle, BoundTypeStaticLine, BoundTypeDynamicLine, BoundTypeNoBound),	bool	> CollisionHandler;	


All your conditional statements are now automatically generated through the voodoo-magic of templates. Calling it is as simple as:

CollisionHandler theCollisionHandler_;
CollisionExecutor theCollisionExecutor_;
theCollisionHandler_.Go(bound1, bound2, theCollisionExecutor_)

The Go member function of theCollisionHandler runs the if-else statements for you, and then delegates execution of the correctly overloaded Fire method in theCollisionExecutor.

Of course, once you've detected a collision, you need to deal with collision response, which is a whole 'nother topic (as I discovered to my chagrin).

Jim.
Quote:Original post by JimPrice
To be fair, one of the loki methods (StaticDispatcher) is just a brute-force dispatcher, albeit 'more c++'.


Indeed but most of the nasty stuff is pushed into the library which is a good thing, and i'm sure some boost MPL and meta-template preprocessor magic could make the process even more automated.

I'm really tempted to re-write some of loki using boost MPL & meta-template preprocessor but i'm lazy and why fix something thats not really broke besides [wink]
I don't have them with me, but I believe one of Scott Meyers Effective C++ books (either Effective C++ or More Effective C++) has a pretty good discussion of exactly what you're talking about. IIRC though he comes to the conclusion that there isn't really a clean way to do it in C++!! Still worth a look though (that goes for those books in general, even if they're slightly out of date)
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

This topic is closed to new replies.

Advertisement