Sign in to follow this  

inheritance problem

This topic is 4248 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm building a particle engine and an having trouble with inheritance. I have a particle struct that contains information like position and color about ine particle, and a particle engine class that updates all the particles and draws them. It contains a virtual function that controls the details of the update, and so I inheret from it classes like smoke and fire which implement it in a certain way. Heres the header for the engine:

#include "3DMath.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <vector>

using namespace std;

struct  SParticle{
    bool	  Active;					
	float	  Life;					
	float	  Fade;	
    //float     Rotation;			
	float	  Red;					
	float	  Green;					
	float	  Blue;	
	float     MultAlpha;
	float     Radius;
    float     RadiusSpeed;		
    float     Rotation;				
	CVector3  Position;					
	CVector3  Direction;						
	CVector3  Gravity;	
    bool      ChangeColor;			

class  CParticleEngine{
   //holds all the particles
   vector<SParticle>   m_vParticles;
   int                 m_iNumberOfParticles;
   float               m_fSlowDown;
   void                InitAllParticles();

   CParticleEngine(int n, CVector3 p);

   CVector3            m_vPosition;
  void Update(double elapsed_time);
  //all entities must implement an init function
  virtual void InitOneParticle(SParticle &particle) = 0;

   CVector3 Vector(){return m_vPosition;}
   float    Number(){return m_vParticles[0].Life;}

class Smoke : public CParticleEngine{
     Smoke(int n, CVector3 p);
     void InitOneParticle(SParticle &particle);


and here's the source file:
#include "ParticleEngine.h"
#include "CCamera.h"
#include <gl\gl.h>

extern GLuint  t_Particles[3];
extern int yay;
extern CCamera Camera;
//  Constructor for SParticle
SParticle :: SParticle()
  Active = true;					
  Life   = 1.0;					
  Fade   = 0;				
  Red    = 1;					
  Green  = 1;					
  Blue   = 1;
  MultAlpha = 1;
  Radius = 10;
  RadiusSpeed = 0.1;		
  Rotation   = 0;			
  Position   = CVector3(0,0,0);					
  Direction  = CVector3(5,5,5);						
  Gravity    = CVector3(0,0,0);
  ChangeColor = false;
// Constructor for CParticleEngine
CParticleEngine :: CParticleEngine(int n, CVector3 p)
  m_vPosition = p;
  m_fSlowDown = 2.0;
  for(int i=0; i<n; ++i)
    // SParticle *particle = new SParticle();
    // m_vParticles.push_back(particle);

// initiates all particles
void CParticleEngine :: InitAllParticles()
  for(int i=0;  i<m_vParticles.size(); i++)
      // m_vParticles[i]->InitParticle(m_vPosition);

//  Updates the particles
void CParticleEngine :: Update(double elapsed_time)
    for (int loop=0;loop<m_vParticles.size();loop++)					// Loop Through All The Particles
            glTranslatef(0, 10, 0);
			float x = m_vParticles[loop].Position.x;
			float y = m_vParticles[loop].Position.y;
			float z = m_vParticles[loop].Position.z;

// Draw The Particle Using Our RGB Values, Fade The 
//Particle Based On It's Life
             float radius = m_vParticles[loop].Radius;
			 glTranslatef(x, y, z);
// Build Quad From A Triangle Strip
			    glTexCoord2d(1,1); glVertex3f(radius,radius,0); 
				glTexCoord2d(0,1); glVertex3f(- 
				glTexCoord2d(1,0); glVertex3f(radius,-
				glTexCoord2d(0,0); glVertex3f(-radius,-
			m_vParticles[loop].Position.x += 
			m_vParticles[loop].Position.y += 
			m_vParticles[loop].Position.z += 

			m_vParticles[loop].Direction.x += 
			m_vParticles[loop].Direction.y += 
			m_vParticles[loop].Direction.z += 
            m_vParticles[loop].Radius += elapsed_time*m_vParticles
            m_vParticles[loop].Life  -= elapsed_time*m_vParticles[loop].Fade;		
            if (m_vParticles[loop].Life<=0.0f)					// If Particle Is Burned Out
Smoke :: Smoke(int n, CVector3 p):CParticleEngine(n, p){}

void  Smoke :: InitOneParticle(SParticle &particle)       
  particle.Active = true;					
  particle.Life   = 1.0;					
  particle.Fade   = (rand()%150)/1000.0f + 0.002;
  particle.MultAlpha = 2.5;			
  particle.Radius    = 10;
  particle.RadiusSpeed = (rand()%150)/1000.0f + 0.002;
  float col = (rand()%600)/1000.0f;

  particle.Red   = col;	// Select Red Rainbow Color
  particle.Green = col;	// Select Red Rainbow Color
  particle.Blue  = col;  
  particle.Rotation  =  (rand()%100)*3.6;  
  //Position  = p;//CVector3(20,20,20);
  particle.Direction = CVector3(float((rand()%50)-26.0f)*0.0f,
  particle.Position = m_vPosition + CVector3(float((rand()%50)-26.0f)*0.15f,
  //CVector3 Direction = CVector3(10,10,0); 
  particle.Gravity   = CVector3(-5,0,0);  

now when I call the constructor like this: Smoke Smoke(1000, CVector3(80,120,80)); I get some kind of runtime error/crash. if I erase the InitAllParticles(); from the ctor then it doesn't crash. Also, if I make the InitOneParticle(SParticle &particle) not virtual, but rather part of CParticleEngine and call the ctor: CParticleEngine ParticleEngine(1000, CVector3(120,120,180)); then it works fine? What is the problem? Thanks.

Share this post

Link to post
Share on other sites
You could have just bumped your other thread you know.

Anyway, I see the problem anyway. You are calling a virtual function from the base class' constructor. Because the derived class hasn't been constructed yet (the base class' constructor is called first) the vtable holds a pointer to the base class' function... which happens to be pure virtual. Boom, crash, etc.

Share this post

Link to post
Share on other sites
You've got other issues too, btw. You prototype initOneParticle without the virtual, then prototype it with virtual and as pure virtual, and then you define a body for it anyway. Isn't your compiler giving you some warnings about this?

Share this post

Link to post
Share on other sites
Oh, I was reading InitAllParticles when I thought that. Forget about it. It's actually the call in the constructor to initallparticles that calls the virtual and makes it crash. Instead; just remove it from the constructor and call it seperatly in the client code, or have update initialize the first time it's called, or something like that.

Share this post

Link to post
Share on other sites
Thanks, it works now. One more question, I'm pretty new to making things with inheritance, is the overall structure of the PE good, are there anythings I should fix/improve?

Share this post

Link to post
Share on other sites
Not really my area of expertise. It looks fugly to me, but I havn't the time nor desire to write you a better one myself.

Share this post

Link to post
Share on other sites
Hard to say. I just don't like it. I'd do something more like

class Particle
static const int UPDATE_DESTROY = 0;
static const int UPDATE_KEEP = 1;
int update();

class Emitter
virtual Particle emit(/*stuff here?*/);

class ParticleSet
std::list<Particle> particles;
Emitter* emitter;
explicit ParticleSet(Emitter* e) : emitter(e) { assert(e); }

void update()
if (should emit more particles) particles.push_back(emitter->emit(/*stuff*/));
for (std::list<Particle>::iterator I = particles.begin(); I != particles.end();)
if (I->update == Particle::UPDATE_DESTROY)
I = particles.erase(I);

Share this post

Link to post
Share on other sites

This topic is 4248 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this