Polymorfism, arv och overloading (c++)

Permalänk
Medlem

Polymorfism, arv och overloading (c++)

Hej hej!
Jag håller på att experimentera med att göra en egen liten händelsebaserad 2d spelmotor (som ska vara enkel att implementera). Jag har lite problem med att "rätt" funktion skall anropas vid kollision. Då kod säger mer än 1000 ord så ger jag ett exempel:

/* Kod från motorn */ class Object { public: virtual void Collision(Object *other) { } }; /* Kod som använder motorn */ class Ball : public Object { }; class Wall : public Object { public: void Collision(Ball* other) { //Denna vill jag ska köras då other "egentligen" är Ball* } void Collision(Wall* other) { //Denna ska köras om det var en vägg som vi kolliderade med (vilket det inte var) } void Collision(Object* other) { //Denna skall köras om ingen annan passar, men som det är nu så körs ju endast denna } }; int main(int argc, char* argv[]) { //Dessa ligger igentligen i en lista Object* enBoll = new Ball(); Object* enVagg = new Wall(); //Här körs lite kod som kollar efter kollisioner, när den hittar en kollision så anropas kollisionsfunktionen på vardera objekt enVagg->Collision(enBoll); enBoll->Collision(enVagg); return 0; }

Ett sätt vore att försöka kasta dem till respektive typ och sedan köra rätt funktion. Men jag vill ju inte att användaren av motorn skall behöva kasta och krångla. Det bästa vore om motorn kunde lösa alla dessa problem. Hur ska jag göra så att rätt funktion anropas?
Hur kan jag göra ett finare kollisions api?

PS.
Reserverar mig för eventuella fel som jag har gjort så här på natten.

Är tacksam för alla idéer och förslag.

Visa signatur

citera!

Permalänk
Medlem

Det du försöker göra med overloading o polymorfism fungerar som sagt inte. Det du behöver är att tillverka något smart sätt runt det hela med hjälp av andra konstruktioner. Det jag tänkte på direkt var att göra någon slags hashmap och funktionspekare till medlemfunktioner och initiera detta i konstruktorn för varje klass. Det är en del tekniska C++ detaljer i detta och säkerligen glömt en hel del "optimeringar" men jag hoppas du fattar vad jag är ute efter.

Jag visar ett exempel nedan;

#include <map> #include <string> class Object; typedef void (Object::*ObjectCallback)(Object *o); typedef std::map<std::string, ObjectCallback> CallbackMap; class Object { public: void collision(Object *other) { CallbackMap::iterator i = callbacks.find(typeid(*other).name()); if (i == callbacks.end()) { // hitta "object" i hashen istället i = callbacks.find(typeid(Object).name()); if (i == callbacks.end()) return; // ingen callback hittad } ObjectCallback cb = i->second; ((*this).*cb)(b); // anropa medlemsfunktion } } // EDIT: snyggare så här :) template<class T, class S> void addCollisionCallback(void(T::*fn)(S*)) { callbacks.insert( std::make_pair(typeid(S).name(), (ObjectCallback)fn) ); } CallbackMap callbacks; }; class Ball : public Object { public: Ball() { } }; class Wall : public Object { public: Wall() { // lägg in alla callbacks //callbacks.insert( std::make_pair(typeid(Ball).name(), (ObjectCallback)(void(Wall::*)(Ball*))&Wall::collision) ); //callbacks.insert( std::make_pair(typeid(Ball).name(), (ObjectCallback)(void(Wall::*)(Wall*))&Wall::collision) ); //callbacks.insert( std::make_pair(typeid(Object).name(), (ObjectCallback)(void(Wall::*)(Object*))&Wall::collision) ); // EDIT: snyggare så här :) addCollisionCallback<Wall,Ball>(&Wall::collision); addCollisionCallback<Wall,Wall>(&Wall::collision); addCollisionCallback<Wall,Object>(&Wall::collision); } void collision(Object *other) { // med andra } void collision(Ball *other) { // boll } void collision(Wall *other) { // vägg } };

Den här

(ObjectCallback)(void(Wall::*)(Object*))&Wall::collision

koden är lite konstig men den måste se ut så här för att hitta rätt funktion av alla som heter "Wall::collision"

Permalänk
Medlem

Jag kan tipsa om att det du försöker göra kallas för multiple dispatch, som C++ inte har något inbyggt stöd för som du märkt. Det går dock att lösa på otaliga sätt, t.ex. som toj_ts lösning, men alla lösningar har alltid både fördelar och nackdelar. Om du googlar efter multiple dispatch så kommer du att hitta en massa olika lösningar.

Permalänk
Medlem
Skrivet av toj_ts:

Det du försöker göra med overloading o polymorfism fungerar som sagt inte. Det du behöver är att tillverka något smart sätt runt det hela med hjälp av andra konstruktioner. Det jag tänkte på direkt var att göra någon slags hashmap och funktionspekare till medlemfunktioner och initiera detta i konstruktorn för varje klass. Det är en del tekniska C++ detaljer i detta och säkerligen glömt en hel del "optimeringar" men jag hoppas du fattar vad jag är ute efter.
...

Hej!
Tack för en briljant lösning! Tyvärr får jag att typeid(*other).name(); alltid returnerar "class Object" och inte den egentliga klassen, med allt vad det innebär. Är det fel hos mig eller ska den göra det?

Skrivet av perost:

Jag kan tipsa om att det du försöker göra kallas för multiple dispatch, som C++ inte har något inbyggt stöd för som du märkt. Det går dock att lösa på otaliga sätt, t.ex. som toj_ts lösning, men alla lösningar har alltid både fördelar och nackdelar. Om du googlar efter multiple dispatch så kommer du att hitta en massa olika lösningar.

"multiple dispatch" heter det alltså! När man får ett namn på problemet så brukar det vara enklare att lösa dem

Visa signatur

citera!

Permalänk
Medlem

Se där, nu lär man sig något nytt. Det finns en hel del att lära inom OOP, synd att man inte gjort något på ett år. Jag vet inte varför din typeid() inte fungerar tyvärr, men kolla på andra lösningar kan vara värt, de är förmodligen snabbare också.

Permalänk
Medlem