child-classes in vector speichern?

TeCe

Erfahrenes Mitglied
Hi...
Bei diesem Thema fällt es mir leider schwer mich gezielt auszudrücken - aber ich versuch's mal so gut ich kann:

Ich habe für einen openGL-TestContainer einen SceneManager, der je nach abgelaufener Zeit zwischen den Scenen wechseln soll.
Das habe ich vorher per
Code:
include "sceneman.h"

CSceneMan::CSceneMan(CTexMan *tex)
{
	dured = 0.0f;

	this->m_tex = tex;
	sc1 = new CScene1(m_tex);
	sc2 = new CScene2(m_tex);
	sc3 = new CScene3(m_tex);
	sc4 = new CScene4(m_tex);
	sc5 = new CScene5(m_tex);
}

CSceneMan::~CSceneMan(void)
{
	delete sc1;
	delete sc2;
	delete sc3;
	delete sc4;
	delete sc5;
}

void CSceneMan::play(GLfloat speed) {
	dured += speed;
	if(dured<sc1->duration)	{
		sc1->play(speed);
	} else if(dured<sc1->duration+sc2->duration) {
		sc2->play(speed);
	} else if(dured<sc1->duration+sc2->duration+sc3->duration) {
		sc3->play(speed);
	} else if(dured<sc1->duration+sc2->duration+sc3->duration+sc4->duration) {
		sc4->play(speed);
	} else if(dured<sc1->duration+sc2->duration+sc3->duration+sc4->duration+sc5->duration) {
		sc5->play(speed);
	
	} else {
		dured = 0.0f;
	}
}
geregelt...da es aber immer mehr Szenen werden und die Spaghettis im code immer länger werden, habe ich mich für ein Stückchen mehr Dynamik entschieden.

Nun hat der SceneManager einen <vector> der die verschiedenen Szenen halten soll:
Code:
void CSceneMan::add(CScene scn) {
	scenes.push_back(scn);
}

CScene ist also die parent-class { mit den Kon-/Destruktor, Basis-Attributen und Methode play(GLfloat speed)} für alle szenen.

Nun sollte doch also per
Code:
scene_manager->add(CScene1(m_tex));
Eine Instanz von CScene1 im scenes-vector stecken!?
Stattdessen erstellt er nur eine Instanz von der parent-class CScene...

Die Methode CSceneMan::play() polymorph für jede einzelne Szene zu gestalten wäre doch schwachsinnig, da kann man ja gleich bei der alten Spaghetti-Methode bleiben...
 
Hallo,
Eine Instanz von CScene1 im scenes-vector stecken!?
Stattdessen erstellt er nur eine Instanz von der parent-class CScene...

es befindet sicherlich ein Objekt vom Typ CScene1 im vector...
Wenn du die Methode play nicht überschreibst, ist es klar das er play nur von der oberklasse aufrufst...

Die Methode CSceneMan::play() polymorph für jede einzelne Szene zu gestalten wäre doch schwachsinnig, da kann man ja gleich bei der alten Spaghetti-Methodebleiben...

Wenn du ein eignes Verhalten für die Methode play für dein Objekt vom Typ CScene1 haben willst überschreib sie, ansonsten lass es bleiben...
Wenn du ein eignes Verhalten + das Basisverhalten haben willst rufe die play
Basismethode in der überschriebenen Methode play auf...

Gruß

RedWIng
 
UI*verwirrung*

Habe mich in der Zeit noch etwas schlau gelesen und bin zu der Entscheidung gekommen, die einzelnen Szenen doch wieder zu instanziieren und deren play()-Methode als virtual zu deklarieren...aber wirklich gefallen tut's mir nicht:
Code:
#include "sceneman.h"

CSceneMan::CSceneMan(CTexMan *tex)
{
	this->dured = 0.0f;

	this->m_tex = tex;

	sc1 = new CScene1(m_tex);
	sc2 = new CScene2(m_tex);
	sc3 = new CScene3(m_tex);
	sc4 = new CScene4(m_tex);
	sc5 = new CScene5(m_tex);

	add(sc1);
	add(sc2);
	add(sc3);
	add(sc4);
	add(sc5);
}

CSceneMan::~CSceneMan(void)
{

	delete sc1;
	delete sc2;
	delete sc3;
	delete sc4;
	delete sc5;
}

void CSceneMan::add(CScene *scn) {
	scene.push_back(scn);
}

void CSceneMan::play(GLfloat speed) {
	this->dured += speed;

	//Berechnen welche Scene grad dran is
	GLfloat scenes_time = 0.0f;
	for(GLuint x=0; x<scene.size(); x++) {
		scenes_time+=scene[x]->duration;
		if(scenes_time>this->dured) return scene[x]->play(speed);
	}
	scene[0]->play(speed);
}
 
Ach verdammt ich hab was überlesen,
du willst sicherlich dynamisch virtuelle Methoden aufrufen?

Dann geht das so nicht:
Code:
void CSceneMan::add(CScene scn) {
	scenes.push_back(scn);
}

Du musst eine Referenz oder einen Pointer verwenden ansonsten greif der
Polymorphismus nicht...

Code:
void CSceneMan::add(CScene* scn) {
	scenes.push_back(scn);
}
Natürlich deinen Vector dementsprechend deklarieren...

P.S. Vielleicht zeigst du auch mal deine Klassendefinition von CScene1 und
CScene.. wobei mir noch auffällt das du dir andere Namen für deine Klassen
ausdenken solltest ;)
Gruß

RedWing
 
Zuletzt bearbeitet:
mmmh...
Auf Pointer hab ich ja grad eh wieder umgestellt...
Aber demnach muss ich ja im code von void CSceneMan::add() abfangen um welche Scene es sich handelt - was ja wieder den Spaghetticode mit sich bringt.

also hier nochmal die angeforderten files:

//scene.h
Code:
#pragma once

#include <windows.h>
#include <gl\gl.h>
#include <math.h>
#include <time.h>
#include "TexMan.h"

class CScene
{
public:
	CScene(CTexMan *tex);
	virtual ~CScene(void);

	virtual void play(GLfloat speed);
	void reset();

	GLfloat dured;
	GLfloat speed;
	GLfloat duration;
	CTexMan *m_tex;
};

//scene.cpp
Code:
#include ".\scene.h"

CScene::CScene(CTexMan *tex)
{
	m_tex = tex;
	dured = 0.0f;
	speed = 0.0f;
}

void CScene::play(GLfloat speed){
	dured+=speed;
	this->speed = speed;
}

CScene::~CScene(void)
{
}

//scene1.h
Code:
#pragma once
#include "scene.h"
#define BLENDS 10+(rand()%10)
class CScene1 : public CScene
{
public:
	CScene1(CTexMan *tex);
	virtual ~CScene1(void);

	virtual void play(GLfloat speed);

};

//scene1.cpp
Code:
#include "scene1.h"

CScene1::CScene1(CTexMan *tex):CScene(tex)
{
	duration = 50.0f;

	m_tex->load("spot");
	m_tex->load("cyl");

	glEnable(GL_TEXTURE_2D);

}

void CScene1::play(GLfloat speed)
{
	dured+=speed;
	this->speed = speed;

	glLoadIdentity();

//Scrolling BG
	glDisable(GL_BLEND);
	glBindTexture(GL_TEXTURE_2D, m_tex->tex("cyl"));

	// TexturBewegung
	static float t =0.0f;
	t += speed*0.003f;

	glBegin(GL_QUADS);
		glTexCoord2f(0,3-t);
		glVertex3f(-900,-15.5,-90);
		glTexCoord2f(3,3-t); 
		glVertex3f(900,-15.5,-90);
		glTexCoord2f(3,0-t); 
		glVertex3f(300,-15.5,50);
		glTexCoord2f(0,0-t); 
		glVertex3f(-300,-15.5,50);
	glEnd();

//Blending Surface
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);
	glPushMatrix();
	glTranslatef(0,0,-1.0f);
	glBindTexture(GL_TEXTURE_2D, m_tex->tex("spot"));
	for(int x=0; x < BLENDS; x++) {
		glPushMatrix();
		glScalef(1-0.03f*x,1-0.03f*x,1);
		glBegin(GL_QUADS);
			glTexCoord2f(0,0);	glVertex3f(-1.0f	,	-1.0f	,	0.0f);
			glTexCoord2f(0,1);	glVertex3f(-1.0f	,	1.0f	,	0.0f);
			glTexCoord2f(1,1);	glVertex3f(1.0f		,	1.0f	,	0.0f);
			glTexCoord2f(1,0);	glVertex3f(1.0f		,	-1.0f	,	0.0f);
		glEnd();
		glPopMatrix();
	}
	glPopMatrix();

}

CScene1::~CScene1(void)
{

}

//sceneman.h
Code:
#pragma once

#include <vector>

#include "Scene.h"
#include "Scene1.h"
#include "Scene2.h"
#include "Scene3.h"
#include "Scene4.h"
#include "Scene5.h"

class CSceneMan
{
public:
	CSceneMan(CTexMan *tex);
	virtual ~CSceneMan(void);

	void play(GLfloat speed);

private:

	CScene1 *sc1;
	CScene2 *sc2;
	CScene3 *sc3;
	CScene4 *sc4;
	CScene5 *sc5;
	GLfloat dured;

	CTexMan *m_tex;

	std::vector<CScene*> scene;
	void add(CScene *scn);
};

//sceneman.cpp
Code:
#include "sceneman.h"

CSceneMan::CSceneMan(CTexMan *tex)
{
	this->dured = 0.0f;

	this->m_tex = tex;

	sc1 = new CScene1(m_tex);
	sc2 = new CScene2(m_tex);
	sc3 = new CScene3(m_tex);
	sc4 = new CScene4(m_tex);
	sc5 = new CScene5(m_tex);

	add(sc1);
	add(sc2);
	add(sc3);
	add(sc4);
	add(sc5);
}

CSceneMan::~CSceneMan(void)
{

	delete sc1;
	delete sc2;
	delete sc3;
	delete sc4;
	delete sc5;
}

void CSceneMan::add(CScene *scn) {
	scene.push_back(scn);
}

void CSceneMan::play(GLfloat speed) {
	this->dured += speed;

	//Berechnen welche Scene grad dran is
	GLfloat scenes_time = 0.0f;
	for(GLuint x=0; x<scene.size(); x++) {
		scenes_time+=scene[x]->duration;
		if(scenes_time>this->dured) return scene[x]->play(speed);
	}
	scene[0]->play(speed);
}

Ich würde gern
Code:
	m_tex = tex;
	dured = 0.0f;
	speed = 0.0f;
nur in der scene.cpp stehen haben, und die Methode play() durch die child-classes erweitern - ist doch eigentlich auch so gedacht - oder überschreib ich standardmässig die Methode der parent-class?
Warum soll ich meine Szenen nicht einfach scene1-n nennen?

Kannst du mir vielleicht die sceneman.cpp entsprechend ändern?
Wüsste wirklich nicht wie ich das anstellen soll, ohne die Szenen vorher zu instanziieren.
Danke, danke
 
nur in der scene.cpp stehen haben, und die Methode play() durch die child-classes erweitern - ist doch eigentlich auch so gedacht
So isses vollkommen richtig
Warum soll ich meine Szenen nicht einfach scene1-n nennen?
CScene1 is so vielsagend
mmmh...Wüsste wirklich nicht wie ich das anstellen soll, ohne die Szenen vorher zu instanziieren.
Da wirst du wohl nich drumrum kommen:
Auf Pointer hab ich ja grad eh wieder umgestellt...
Aber demnach muss ich ja im code von void CSceneMan::add() abfangen um welche Scene es sich handelt - was ja wieder den Spaghetticode mit sich bringt.

Nein brauchst du nicht das übernimmt ja der virtual Mechanismus für dich...

Deine CSceneMan.h sollte allerdings so auscchauen:

Code:
...
class CSceneMan
{
public:
	CSceneMan(CTexMan *tex);
	virtual ~CSceneMan(void);

	void play(GLfloat speed);

private:

	CScene *sc1;
	CScene *sc2;
	CScene *sc3;
	CScene *sc4;
	CScene *sc5;
	GLfloat dured;

	CTexMan *m_tex;

	std::vector<CScene*> scene;
	void add(CScene *scn);
};....

Und die CSceneMan.cpp wie gehabt dann sollte es eigentlich so klappen....

oder so wenn du die member nicht brauchst:
Code:
...
class CSceneMan
{
public:
	CSceneMan(CTexMan *tex);
	virtual ~CSceneMan(void);

	void play(GLfloat speed);

private:
	GLfloat dured;

	CTexMan *m_tex;

	std::vector<CScene*> scene;
	void add(CScene *scn);
};....

Dann dein Construktor so:
Code:
CSceneMan::CSceneMan(CTexMan *tex)
{
	this->dured = 0.0f;

	this->m_tex = tex;

	add(new CScene1(m_tex));
	add(new CScene2(m_tex));
	add(new CScene3(m_tex));
	add(new CScene4(m_tex));
	add(new CScene5(m_tex));
}

Bitte nicht vergessen die Elemente des vectors wieder freizugeben

Gruß

RedWing
 
Zuletzt bearbeitet:
Hmmm...es funktioniert

aber sowas wie
Code:
add(new CScene1(m_tex));
hab ich echt noch nie gesehen!
...also new Class() als Parameter gibt automatisch einen Pointer mit...klar *pointer = new Class() ist ja auch nichts anderes ;-)

//der Destructor
Code:
CSceneMan::~CSceneMan(void)
{
	for(GLuint x=(GLuint)scene.size(); x>0; x--) {
		delete scene[x];
	}
}
sollte ja hoffentlich das Richtige bewirken.

Super - so gute Hilfestellung hab ich schon lange nicht mehr bekommen!
 
//der Destructor
Code:
CSceneMan::~CSceneMan(void) { 
                       for(GLuint x=(GLuint)scene.size(); x>0; x--) { 
                                       delete scene[x]; 
                       } 
}

sollte ja hoffentlich das Richtige bewirken.

Thats right...

Super - so gute Hilfestellung hab ich schon lange nicht mehr bekommen!

Wenn das ein Kompliment sein sollte fass ich es als solches auf und danke dir :)

Gruß

RedWing
 
Aehm mom

Code:
CSceneMan::~CSceneMan(void)
{
	for(GLuint x=(GLuint)(scene.size() - 1); x>=0; x--) {
		delete scene[x];
	}
}

So is besser ;)

Gruß

RedWing
 
Whaat?

Es gibt 10 verschiedene Menschen auf dieser Welt - die, die Binärzahlen kennen und die, die sie nicht kennen - oder so ähnlich...wo ist denn da bitte der unterschied?

Code:
CSceneMan::~CSceneMan(void)
{
	for(GLuint x=sqrt(GLuint(scene.size()*scene.size())) - sin(90); x>=NULL; x-1) {
		delete scene[x];
	}
}
 
Zuletzt bearbeitet:
Zurück