Compiler error on pointer conversion

The compiler is all angry about…

fun_4-3-2015.ino: In function ‘void doSparkles()’:
fun_4-3-2015.ino:90:16: error: invalid conversion from ‘linkListObj*’ to ‘sparkle*’ [-fpermissive]

A sparkle is derived from linkListObj.

Here’s the calling routine…

void doSparkles(void) {
  
  int      index;
  colorObj backgroundColor;
  colorObj result;
  sparkle* sparklePtr;
  
  sparklePtr = sparkles.getSparkles();
  while(sparklePtr) {
    index = sparklePtr->getIndex();
    backgroundColor = lightStick.getPixelColor(index);
    result = sparklePtr->getColor(&backgroundColor);
    lightStick.setPixelColor(index, &result);
    sparklePtr = sparklePtr->next;
  }
  lightStick.show();
}

And here’s sparkle.h file for sparkles & sparkleList

#include <colorObj.h>
#include <idlers.h>
#include <lists.h>
#include <multiMap.h>
#include <timeObj.h>

#define DEF_ONTIME 20  // ms


class sparkle : public linkListObj {
  
  public :
            sparkle(int inIndex, colorObj* color=&white, float onTime=DEF_ONTIME, float dormantTime=0, float buildTime=0, float decayTime=0);
            ~sparkle(void);
  
          boolean   checkSparkle(void);
          colorObj  getColor(colorObj * backgroundColor);
          int       getIndex(void);
  
  protected :
  
  int          index;
  colorObj     baseColor;
  multiMap     blendMapper;
  timeObj*      lifeTimer;
};
  
  
  
class sparkleList : public linkList, public idler {
    
    public :
                      sparkleList(void);
                      ~sparkleList(void);
                      
                sparkle*  getSparkles(void);
        virtual void      idle(void);
  };

The sparkle.cpp file…

#include "sparkle.h"

sparkle::sparkle(int inIndex, colorObj* color, float onTime, float dormantTime, float buildTime, float decayTime) {

  unsigned int startTime = micros();
  unsigned int time = startTime;
  index = inIndex;
  baseColor = *color;
  if (onTime<=0) onTime=1;
  if (dormantTime<=0) dormantTime=1;
  if (buildTime<=0) buildTime=1;
  if (decayTime<=0) decayTime=1;
  blendMapper.addPoint(time,0);
  time = time + dormantTime;
  blendMapper.addPoint(time,0);
  time = time + buildTime;
  blendMapper.addPoint(time,100);
  time = time + onTime;
  blendMapper.addPoint(time,100);
  time = time + decayTime;
  blendMapper.addPoint(time,0);
  lifeTimer = new timeObj(time-startTime);
  lifeTimer->start();
}


sparkle::~sparkle(void) { if (lifeTimer) delete(lifeTimer); }


// Check to see if this sparkle is still alive.
boolean sparkle::checkSparkle(void) { return !lifeTimer->ding(); }


// Calculate the color to display at this time.
colorObj sparkle::getColor(colorObj * backgroundColor) { return baseColor.blend(backgroundColor,blendMapper.Map(micros())); }


// Our location in the list of pixles.
int sparkle::getIndex(void) { return index; }


// Create a list to dump sparkles into. The list ownes them and will garbage collect
// them during idle time. REMEBER to call hookup() to start the garbage collection.
sparkleList::sparkleList(void) : linkList(true) {  }


sparkleList::~sparkleList(void) {  }


// People are going to want to access the sparkles. Here's a pointer to the list of them.
sparkle* sparkleList::getSparkles(void) { return (sparkle*)getList();  }  /* TROUBLE HERE */

 
// Don't have a lot of time for idle(). So we knock off one ony (1) dead node.       
void  sparkleList::idle(void) {
   
  if (!isEmpty()) {                                // Should we bother?
    sparkle* trace = (sparkle*)theList;            // A pointer to the top of the non-empty list;
    while(trace->checkSparkle()&&trace->next) {    // If this one is ok, and there is a next one..
      trace = trace->next;                         // Go to the next one.
    }
    if (!trace->checkSparkle()) {                  // Either this one was dead or it was the last one. (We forgot, so ask again.)
      deleteObj(trace);                            // Ah! this one's dead, delete it.
    } 
  }
}                                                  // And we're out of time!

You need to provide an explicit cast.

class A {
   int foo;
};

class B : public A {
   int bar;
};

void setup() {
  
  B obj;
  
  A *a = &obj;
  
  B *b = (B*) a;  //Cast needed, pointers are not compatible.

}

void loop(){}

Why aren't they compatible?

When using base objects, referenced from derived objects, the derived members are effectively sliced off: http://stackoverflow.com/a/274634/4057102

Hmm…

From what I read on that link. It -seems- that…

sparkle* sparkleList::getSparkles(void) { return dynamic_cast<sparkle*>theList;  }

Should work.
Cause I read “Bar* bar = dynamic_cast<Bar*>(base);”

And for me…
Sparkle is the “Bar” derived class of linkListObj “base”

But its having no effect… Am I on the right trail here?

Thanks!

-jim lee

dynamic_cast is intended for use with derived types, not bases.

class B; //Forward declaration

class A {
  public:
   int foo;
   B *getB();
};

class B : public A {
   int bar;
};

B *A::getB(){ return (B*) this; }

void setup() {
  
  B obj;
  
  A *a = &obj;
  
  B *b = (B*) a;
  
  dynamic_cast<A*>(&obj);  //Works
  dynamic_cast<B*>(a);     //Error
  
  a->getB(); //Works
}

void loop(){}

Ok, thanks.

Fixed!

-jim lee