Archief - [PROG][C++] Dynamic dispatching

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

forloRn_

Legacy Member
Gegroet,

Ben een platformspel aan het maken.

De zichtbare voorwerpen in het spel (speler, vijand, blokje, projectiel, ...) behoren tot de superklasse Entity.
AvatarOne is de voorstelling van speler 1 in het spel (bevat concrete sprites en bewegingen). Zij is via Creature en Avatar een subklasse van Entity.

De hiërarchie gaat dus als volgt:

Entity <- Creature <- Avatar <- AvatarOne

De methode update() in Entity.h heb ik zo gedeclareerd:
Code:
virtual void update(int delta);

Zij bevat een default implementatie in Entity.cpp:
Code:
void Entity::update(int delta) {
	position += velocity * delta / 1000;
}

De bedoeling is dat AvatarOne deze methode override. Declaratie in AvatarOne.h:
Code:
void update(int delta);

Implementatie in AvatarOne.cpp:
Code:
void AvatarOne::update(int delta) {
	std::cout << "In update() van AvatarOne!" << std::endl;

	Entity::update(delta);
	
	time_elapsed += t.elapsed();
	if(time_elapsed > 1000) {
		advanceFrame();
		time_elapsed = 0;
		t.start();
	}
}

Ze roept dus Entity::update() aan, en voegt zelf nog wat code toe omtrent de animatie. Vreemd genoeg wordt nooit AvatarOne::update() aangeroepen, maar Entity::update(). Ik dacht dat virtual er voor zorgde dat er dynamic dispatching (of dynamic binding, zo u wil) toegepast werd?

De plaats waar update() aangeroepen wordt is in de klasse Level, die een lijst bijhoudt van al de Entities in dat Level:

Code:
void Level::update(int delta, QPainter &painter) {
	/* Het updaten en tekenen wordt naar de entities zelf gedelegatet */
	for(unsigned int i = 0; i < entities.size(); i++) {
		entities[i]->update(delta);
		entities[i]->paint(painter, 0, 0);
	}
}

Declaratie van entities in Level.h:
Code:
vector<Entity *> entities;

En zo voeg ik tenslotte Entities toe aan het level:
Code:
void Level::addEntity(Entity *e) {
	entities.push_back(e);
}

en elders:
Code:
AvatarOne *av = new AvatarOne(player);
addEntity(av);

Conclusie: ik krijg mijn ventje op het scherm, maar het is niet geanimeerd, omdat het Entity::update() aanroept in plaats van AvatarOne::update().

Waarom?

Krueger

Legacy Member
Code:
void Level::update(int delta, QPainter &painter) {
	/* Het updaten en tekenen wordt naar de entities zelf gedelegatet */
	for(unsigned int i = 0; i < entities.size(); i++) {
		entities[i]->update(delta);
		entities[i]->paint(painter, 0, 0);
	}
}

Klein gokje, moet je hier je entity niet casten naar het type avater(in het geval de entity een avater is uiteraard), en er dan de functie update van oproepen?

forloRn_

Legacy Member
Daar had ik ook al aan gedacht. Ik hoopte dat het gemakkelijker ging.

Vich

Legacy Member
Krueger zei:
Code:
void Level::update(int delta, QPainter &painter) {
	/* Het updaten en tekenen wordt naar de entities zelf gedelegatet */
	for(unsigned int i = 0; i < entities.size(); i++) {
		entities[i]->update(delta);
		entities[i]->paint(painter, 0, 0);
	}
}

Klein gokje, moet je hier je entity niet casten naar het type avater(in het geval de entity een avater is uiteraard), en er dan de functie update van oproepen?

Nee, dat is absoluut niet nodig. Als je iets virtual override, dan wordt altijd het hoogste object in de hierarchie aangeroepen, dus AvatarOne::Update zou moeten worden aangeroepen.
Als dat niet zo is - zoals de TS meldt - dan moet hij zijn definitie nakijken in de header file van AvatarOne, want die zal niet exact hetzelfde zijn als die van Entity.

@TS: Je kan best die 2 header files even posten denk ik. Hoe zeker ben je dat hij niet in de update komt: heb je via breakpoints de update route wel getraced?

forloRn_

Legacy Member
Heb ondertussen wat aan de rest van de code geprutst (die er compleet los van staat), opnieuw gecompileerd en nu werkt het wel! :doh: Om zot van te worden!

killgore

Legacy Member
forloRn_ zei:
Heb ondertussen wat aan de rest van de code geprutst (die er compleet los van staat), opnieuw gecompileerd en nu werkt het wel! :doh: Om zot van te worden!
asge vs gebruikt: bij zulke problemen eens full rebuild doen, sommige zaken worden (ook al zijn ze aangepast) niet altijd gehercompileerd. Het kan best zijn dat hij hem nog als non-virtual gecompileerd had staan. in nieuwste visual c++ express zijn de problemen bij mijn weten al opgelost, maar in oudere versies heb ek er van tijd nog last van (vreselijk ambetant bij binding-problemen). bij dev-cpp heb ik van zoiets geen last gehad, andere compilers weet ek niet :).

Kheb het probleem vaak genoeg tegengekomen toen ek vo hl2 modde :) (nadeel daar is dat full rebuild immens lang duurt).

forloRn_

Legacy Member
Ik programmeer in Eclipse met de CDT-plugin. Normaal gezien onder Linux maar nu tijdelijk onder Windows met MinGW32-compiler.
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan