So, I create a State class. In that State class's create function, it creates a StateVisual class by calling the StateVisual class's create function, passing itself as a parameter. (The parameter is a reference so that there is no copying). The StateVisual then sets the parameter (The State Instance), as it's parent variable, which is a pointer of a State type.
In the StateVisual's create function, everything works fine. However, when you get to it's update method, and try to print it's parent size, it prints some weird value.
#ifndef STATE_H
#define STATE_H
#include "cocos2d.h"
class StateVisual;
class State {
public:
State();
~State();
static State create();
StateVisual *visual;
float size;
void setSize(float);
void update(float);
private:
cocos2d::Scheduler* _scheduler;
};
#endif
StateVisual.cpp
#ifndef STATE_VIS_H
#define STATE_VIS_H
#include "cocos2d.h"
#include "State.h"
class StateVisual : public cocos2d::Sprite {
public:
StateVisual();
~StateVisual();
// create a visual
State* parent;
static StateVisual* create(State& parent);
cocos2d::Label* label;
void setSize(float);
void update(float);
private:
bool _activated;
float _size;
};
#endif
State.cpp
#include "State.h"
#include "GameScene.h"
State::State() : size(0) {
CCLOG("Created");
}
State::~State() {
}
void State::setSize(float newSize) {
size = newSize;
CCLOG("%f, %f", newSize, size);
}
void State::update(float dt) {
}
State State::create() {
State state;
state.visual = StateVisual::create(state);
cocos2d::SEL_SCHEDULE ss;
return state;
}
StateVisual.cpp
#include "StateVisual.h"
#include "GameScene.h"
using namespace cocos2d;
StateVisual::StateVisual() : parent(nullptr) {
CCLOG("New STATE VISUAL!");
}
StateVisual::~StateVisual() {
}
void StateVisual::setSize(float size) {
setContentSize(Size(size, size));
if (size > 30) {
label->setSystemFontSize(size*.1);
label->setOpacity(255);
}
else {
label->setOpacity(0);
}
}
void StateVisual::update(float dt) {
cocos2d::MathUtil::smooth(&_size, parent->size, dt, .2);
setSize(_size);
CCLOG("%f, %f", _size, (*this->parent).size);
}
StateVisual* StateVisual::create(State &parent) {
StateVisual* visual(new StateVisual());
if (visual->initWithFile("Circle.png"))
{
visual->setSize(200);
visual->_size = 200;
visual->parent = &parent;
visual->parent->setSize(20);
CCLOG("PARENT SIZE: %f", visual->parent->size);
visual->autorelease();
visual->scheduleUpdate();
return visual;
}
CC_SAFE_DELETE(visual);
return NULL;
}
It outputs:
Created
New STATE VISUAL!
cocos2d: fullPathForFilename: No file found at /cc_2x2_white_image. Possible
missing file.
20.000000, 20.000000
PARENT SIZE: 20.000000
500.000000, 500.000000
cocos2d: QuadCommand: resizing index size from [-1] to [2560]
168.058044, -107374176.000000 <-- Those are the weird values it prints
155.130508, -107374176.000000
The program '[1464] State.exe' has exited with code 0 (0x0).
0xCCCCCCCC, a typical value used to fill uninitialized memory in Debug builds, interpreted as a 32-bit float, equals -107374176.000000. You're printing an uninitialized float value.
State State::create() {
State state;
state.visual = StateVisual::create(state);
cocos2d::SEL_SCHEDULE ss;
return state;
}
At the end of this function the local object state is destroyed a copy ois made (or moved to a new object). Which means any pointer to the address &state is invalid after the end of State::create
visual->parent = &parent; // parent = state object on stack
Because of this line visual->parent is now dangling.
Those weird values are the random content of you thread stack...
What you should do is use shared pointers for state\parent.
void StateVisual::update(float dt) {
cocos2d::MathUtil::smooth(&_size, parent->size, dt, .2);
setSize(_size);
CCLOG("%f, %f", _size, (*this->parent).size);
Why do you use parent->size in 1 row of function and (*this->parent).size in third?
Why don't you use getters and setters?
Why haven't you shown header files?
Why haven't you prepared minimal example (like just parent-child logic and sizes without labels, positions etc.?
What is this suposed to do? StateVisual* visual(new StateVisual());
If visual is automatic variable, i think it should look loke StateVisual visual(new StateVisual()); otherwise shouldn't it be StateVisual* visual = new StateVisual(new StateVisual()); Also are you sure you want to pass new StateVisual object into constructor of StateVisual?
Related
It seems that, when I pass an class it is not passing a persistant (the same) instance of that class as I would expect. I'm assuming this has something to do with memory state but I would appreciate it if someone could explain exactly what is happening. The issue is easily demonstrated as follows :
Main.ino
#include "Debug.h"
#include "Box.h"
Debug debug;
Box box(debug);
void loop(){
debug.message("loop");
debug.line();
}
void setup(){
debug.init();
box.init();
debug.message("Setup Complete");
debug.line();
}
Debug.h
#ifndef DEBUG_H
#define DEBUG_H
class Debug {
private:
bool state;
public:
Debug();
void init();
void message(const char *str);
void message(int);
void line();
};
#endif
Debug.cpp
#include "Debug.h"
#include <Arduino.h>
Debug::Debug() : state(false) {}
void Debug::init() {
if (state == false){
Serial.begin(9600);
state = true;
}
}
void Debug::message(const char *messageChar) {
if (state){
const char *p;
p = messageChar;
while (*p) {
Serial.print(*p);
p++;
}
}
}
void Debug::message(int messageInt) {
if (state){
Serial.print(messageInt);
}
}
void Debug::line() {
if (state){
Serial.println();
}
}
Box.h
#ifndef BOX_H
#define BOX_H
#include "Debug.h"
class Box {
private:
Debug debug;
public:
Box(Debug &debug);
void init();
};
#endif
Box.cpp
#include "Box.h"
#include <Arduino.h>
Box::Box(Debug &debug):
debug(debug)
{}
void Box::init(){
// Switches
pinMode(28, INPUT_PULLUP);
debug.message("Box intialized");
debug.line();
}
So the above code outputs to serial:
Setup Complete
If I modify Box::init() to
void Box::init(){
// Switches
pinMode(28, INPUT_PULLUP);
debug.init();
debug.message("Box intialized");
debug.line();
}
I get what I want :
Box initialized
Setup Complete
If I get rid of Box constructor class and instead do
void Box::init(Debug &debug){
this->debug = debug;
// Switches
pinMode(28, INPUT_PULLUP);
debug.message("Box intialized");
debug.line();
}
Called via Main.ino like
void setup(){
debug.init();
box.init(debug);
debug.message("Setup Complete");
debug.line();
}
I get the desired response again. I don't understand why my first attempt doesn't work nor do I feel comfortable knowing what best practices are. I would appreciate any guidance.
You have two Debug values in your code. One global, one member of the Box class.
Those are two distinct values, since Box create or copy from a value to create its own, and there's the global one.
A solution would be to contain a reference or a pointer.
Here's the example with a reference:
class Box {
private:
Debug& debug;
// ^---- there
public:
Box(Debug &debug);
void init();
};
If you want Box to still be assignable, then use a pointer:
class Box {
private:
Debug* debug;
// ^---- now it's a star
public:
Box(Debug &debug);
void init();
};
Box::Box(Debug &debug):
debug(&debug)
{} // ^----- here, we take the address of the debug variable.
Since references are immutable, you loose some important feature of the language: assignment.
struct thing {
int& ref;
};
int main () {
int a, b;
thing t1{a}, t2{b};
t1 = t2; // ERROR!
}
The assignment would cause t1.ref to point to b after the assignment.
Pointer has a more difficult syntax and hard to guess semantics. However, they play very well with assignment since they give you more freedom:
struct thing {
int* ptr;
};
int main () {
int a, b;
thing t1{&a}, t2{&b};
t1 = t2; // Works, t1.ptr points to b
}
I'm programming an ESP32 UI and have run into this issue:
I have a class Menu, and define a vector _menuItemStack in its header.
I create an Object MenuItem from outside and pass it to the function addMenuItem(MenuItem menuItem). It adds it to the stack. Which works, when I declare the vector in the Menu.cpp it runs. But it won't be unique for each object, I think it becomes static?
So I declared the vector as private in the header, while it will compile. it crashes immediately.
What is my mistake? C++ makes my head hurt.
Menu.h
/*
Menu.h - Menu Class
*/
#ifndef Menu_h
#define Menu_h
#include "Arduino.h"
#include "StackArray.h"
#include "MenuItem.h"
#include "SPI.h"
#include "U8g2lib.h"
class Menu
{
public:
Menu();
void update();
void draw();
void addMenuItem(MenuItem menuItem);
private:
int arrayPos;
std::vector<MenuItem> _menuItemStack;
};
#endif
Menu.cpp
#include "Menu.h"
extern U8G2_SSD1327_MIDAS_128X128_2_4W_HW_SPI u8g2;
Menu::Menu() {
arrayPos = 0;
}
void Menu::draw() {
u8g2.setFont(u8g2_font_6x10_tf);
int posY = 0;
for (MenuItem &m : _menuItemStack){
u8g2.drawStr(0,posY+15,m.getText().c_str());
posY+=15;
}
}
void Menu::update() {
}
void Menu::addMenuItem(MenuItem menuItem){
arrayPos++;
_menuItemStack.push_back(menuItem);
//debug
Serial.println(arrayPos);
Serial.println(menuItem.getText());
}
Notes: the std::stdlib is included higher up.
EDIT:
MenuItem.cpp
#include "MenuItem.h"
extern U8G2_SSD1327_MIDAS_128X128_2_4W_HW_SPI u8g2;
MenuItem::MenuItem() {
_text = new String;
}
MenuItem::MenuItem(const MenuItem &obj){
_text = new String;
*_text = *obj._text;
}
void MenuItem::draw(){
}
void MenuItem::update(){
}
void MenuItem::setText(String txt){
*_text = txt;
}
String MenuItem::getText(){
return *_text;
}
void MenuItem::attachHandler(CallbackFunction f){
callback = f;
}
void MenuItem::run(){
if (callback != NULL) callback();
}
MenuItem.h
#ifndef MenuItem_h
#define MenuItem_h
#include "Arduino.h"
#include "StackArray.h"
#include "SPI.h"
#include "U8g2lib.h"
class MenuItem
{
private:
typedef void (*CallbackFunction)();
CallbackFunction callback = NULL;
String *_text;
public:
MenuItem();
MenuItem(const MenuItem &obj);
void draw();
void update();
void run();
void setText(String txt);
void attachHandler(CallbackFunction f);
String getText();
};
#endif
The menuItem passed into the addMenuItem function is a copy that has a lifespan until the end of that function.
Try passing in the menu item as a reference so that your list of menu items will be populated with objects that have a lifespan longer than the addMenuItem function. That change the signature to look like this:
void Menu::addMenuItem(MenuItem& menuItem)
When you call std::vector::push_back you create a copy of your object and store it into the vector. So first check, the copy constructor of your class and if the error could be caused by this.
Then you need to know where is stored the memory necessary for std::vector.
On embedded target you may not be using the traditional standard library and manipulating memory can be tricky.
When you declare your vector as a global variable, it is highly probable that the memory required is not in the same zone than when you declare it as a private member of a class. This will depend on your platform, compiler, linker script, and the lib C++ your are using. std::vector use an allocator, on Linux you can get away without looking at what it does, when on embedded target you need to know which allocator your are using and where the memory is.
You can try to print the address of std::vector::data() to check that. Then you will probably have to either provide your own allocator or to reserve a portion of memory large enough to hold the vector and initialize the data contained in your vector at this memory address.
I'm currently developing a nodejs module, written in C++ and I've been looking for a way to convert a v8::Object to a cv::Mat object from opencv, without any luck for now.
I saw that nan library could help to convert objects, but i couldn't find how, I don't even know if it's possible to convert them in my case.
The v8 juice project would meet my expectations but since it has been abandoned, I just don't know how to do this.
Here is a snippet of what I'm trying to do :
void
BRMatcher::run(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
if (args.Length() < 1)
{
isolate->ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, "Missing parameter [Mat img].")));
return ;
}
if (!args[0]->IsObject())
{
isolate->ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, "Parameter [Mat img] must be an object.")));
return ;
}
v8::Local<v8::Object> cvMat(args[0]->ToObject());
Mat img = ??? // This is where I ended up...
// ...
}
All the posts talking about this on StackOverflow are outdated (older versions or tools that are not working anymore...)
So my questions are: how can I convert the argument I receive in my function to a cv::Mat object ? To any type I want ?
Any help would be appreciated, thanks!
At first I would recommend to look on existing openCV bindings for Node.js like node-opencv.
If you need to bind C++ and JavaScript code, there are several libraries. As an author of one of them, v8pp, I know about several other:
vu8 (abandoned)
v8-juice (abandoned)
Script bindng in cpgf
Embind
As I know, to convert a C++ object into v8::Object all of them use v8::Object::SetAlignedPointerInInternalField() function.
C++ object to v8::Object conversions are usually performed with mapping of a C++ pointer to persistent handle of the V8 object in a map container.
Do have a look on the Nodejs.org C++ addon and Nan tutorials. Though both are a little misleading, they anyhow describe the canonical way. Use Nan over direct V8 APIs since especially this part (was and still) is changing a lot.
With Nan what you're looking for is passing wrapped objects. More precisely this line is the heart of it.
In this fork of Node-OpenCV, I am doing exactly that with cv::Mat in order to make it a first class object for JS-land. Maybe this implementation may help you.
TL;DR
Wrap the object with Nan::ObjectWrap and pass it around. Internally uses v8::SetInternalFieldPointer(); for you. This is basically copy-paste-able.
// lib/mat.js
var cv = require('./bindings')('addon');
function Mat() {
}
/**
* returns the wrapped c++ object
* [arguments optional]
*/
Mat.prototype.createMat = function (a) {
var args = Array.prototype.slice.call(arguments);
return cv.Mat.createMat(args[0])
}
// src/addon.cc
// just initializes all your modules. Magic happening in mat.h and matwrap.h
// matwrap.cc is the implementation of the wrapped object. mat.cc holds
// JS-libarary specific methods
#include <nan.h>
#include "opencv.h"
#include "imgproc.h"
#include "mat.h"
#include "matwrap.h"
void InitAll(v8::Local<v8::Object> exports) {
Opencv::Init(exports);
ImgProc::Init(exports);
Matwrap::Init();
Mat::Init(exports);
}
NODE_MODULE(addon, InitAll)
Important stuff here...
// src/matwrap.h
#ifndef MATWRAP_H
#define MATWRAP_H
#include <opencv2/opencv.hpp>
#include <nan.h>
class Matwrap : public Nan::ObjectWrap {
public:
static void Init();
static v8::Local<v8::Object> NewInstance(v8::Local<v8::Value> arg);
cv::Mat Val() const { return val_; }
private:
Matwrap();
~Matwrap();
static Nan::Persistent<v8::Function> constructor;
static void New(const Nan::FunctionCallbackInfo<v8::Value>& info);
cv::Mat val_;
};
#endif
...and here you're are wrapping it (basically that's it; follow below for consumption):
// src/matwrap.cc
#include <node.h>
#include "matwrap.h"
#include <opencv2/opencv.hpp>
Matwrap::Matwrap() {};
Matwrap::~Matwrap() {};
Nan::Persistent<v8::Function> Matwrap::constructor;
void Matwrap::Init() {
Nan::HandleScope scope;
// Prepare constructor template
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Matwrap").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
constructor.Reset(tpl->GetFunction());
}
void Matwrap::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
// wrap it...
Matwrap* obj = new Matwrap();
cv::Mat src;
obj->val_ = src;
obj->Wrap(info.This());
// return wrapped here...
info.GetReturnValue().Set(info.This());
}
v8::Local<v8::Object> Matwrap::NewInstance(v8::Local<v8::Value> arg) {
Nan::EscapableHandleScope scope;
// const unsigned argc = 1;
// v8::Local<v8::Value> argv[argc] = { arg };
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
v8::Local<v8::Object> instance = cons->NewInstance();
return scope.Escape(instance);
}
For consumption you could do stuff like this:
// lib/mat.js
/**
* Returns true if the array has no elements.
* #param {Object} mat - native cv::Mat
* #return {Boolean}
*/
Mat.prototype.empty = function (mat) {
var args = Array.prototype.slice.call(arguments);
return cv.Mat.empty(args[0])
}
// src/mat.h
// This is your API
#ifndef MAT_H
#define MAT_H
// #include <opencv2/opencv.hpp>
#include <nan.h>
class Mat : public Nan::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
private:
explicit Mat(double value = 0);
~Mat();
static void New(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void CreateMat(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Empty(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Total(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Type(const Nan::FunctionCallbackInfo<v8::Value>& info);
static Nan::Persistent<v8::Function> constructor;
double value_;
};
#endif
// src/mat.cc
#include "mat.h"
#include "matwrap.h"
#include <opencv2/opencv.hpp>
Nan::Persistent<v8::Function> Mat::constructor;
Mat::Mat(double value) : value_(value) {
}
Mat::~Mat() {
}
void Mat::Init(v8::Local<v8::Object> exports) {
Nan::HandleScope scope;
// Prepare constructor template
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Mat").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
Nan::SetPrototypeMethod(tpl, "createMat", CreateMat);
Nan::SetPrototypeMethod(tpl, "empty", Empty);
Nan::SetPrototypeMethod(tpl, "total", Total);
Nan::SetPrototypeMethod(tpl, "type", Type);
constructor.Reset(tpl->GetFunction());
exports->Set(Nan::New("Mat").ToLocalChecked(), tpl->GetFunction());
}
void Mat::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
if (info.IsConstructCall()) {
// Invoked as constructor: `new Opencv(...)`
double value = info[0]->IsUndefined() ? 0 : info[0]->NumberValue();
Mat* obj = new Mat(value);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
// Invoked as plain function `Opencv(...)`, turn into construct call.
const int argc = 1;
v8::Local<v8::Value> argv[argc] = { info[0] };
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
info.GetReturnValue().Set(cons->NewInstance(argc, argv));
}
}
void Mat::CreateMat(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Matwrap::NewInstance(info[0]));
}
void Mat::Empty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
Matwrap* obj = Nan::ObjectWrap::Unwrap<Matwrap>(info[0]->ToObject());
// check through cv::Mat::empty()
if (obj->Val().empty()) {
// return JS bool
info.GetReturnValue().Set(Nan::True());
} else {
// TODO: logically not correct
info.GetReturnValue().Set(Nan::False());
}
}
How can an object access a variable belonging the class containing it?
Right now I have a class called system that contains some other objects, and those objects need to access and modify one of the variables in the System class.
Example:
Class System {
BlockA _blockA = new BlockA();
BlockB _blockB = new BlockB();
BlockC _blockC = new BlockC();
BlockD _blockD = new BlockD();
int myVariable;
...stuff...
}
Class BlockA {
...stuff...
void someFunction () {
System.myVariable++;
}
...stuff...
}
etc...
Alright so I thought about this some more and realized that when initializing the objects, I will pass a pointer to the variable of interest. That way all objects can read that variable. For anyone else with this problem, if you need to write, you'll have to make sure that the variable is atomic.
Hard to know exactly what you're after, but appears something along these lines:
#BlockA.h
#ifndef BLOCKA_H
#define BLOCKA_H
class System;
class BlockA {
System* sys;
public:
BlockA(System* sys) : sys(sys) {}
void SomeFunction();
};
#endif // BLOCKA_H
#BlockA.cpp
#include "System.h"
void BlockA::SomeFunction() {
sys->setMyVariable(sys->getMyVariable() + 1);
}
#System.h
#ifndef SYSTEM_H
#define SYSTEM_H
class BlockA;
class System {
BlockA* _blockA;
int myVariable;
public:
System();
int getMyVariable() const;
void setMyVariable(int value);
BlockA& getBlockA() const;
};
#endif // SYSTEM_H
#System.cpp
#include "System.h"
#include "BlockA.h"
System::System()
: _blockA(new BlockA(this)) { }
int System::getMyVariable() const {
return myVariable;
}
void System::setMyVariable(int value) {
myVariable = value;
}
BlockA& System::getBlockA() const {
return *_blockA;
}
I'm programming some arduino code, but things aren't quite going to plan.
What am I doing wrong here? I've read around and tried to educate myself about virtual functions, but perhaps I've missed something. Go to QUESTIONSHERE for the actual questions to which I need answers, but first, some explanation:
The Classes RGBPixel and colorGenerator both derive from colorSource, which provides public functions getR(), getG() and getB() so that another pixel or color modifier can take a copy of their current colour.
Classes derived from colorGenerator implement the colour generation code so that they can generate their own colour, while RGBPixels have a colorSource *parent member, so they can obtain a color value from a colorGenerator or another RGBPixel.
In my example, I have one colorGenerator subclass (CG_EmeraldWaters, which should create me a variety of greens and blues), and then a number of RGBPixels in an array. RGBPixels[0] should take its value from an instance of GC_EmeraldWaters, while RGBPixels[1] takes its value from RGBPixels[0], [2] from [1], [n] from [n-1]. The pixels seem to be pulling a color from their parent just fine, but either the first pixel in the chain isn't querying the colorGenerator properly, or the colorGenerator isn't updating properly.
To update the colorGenerator, a colorController class oversees the whole process:
colorController.h:
#ifndef _COLORCONTROLLER_H
#define _COLORCONTROLLER_H
#include <list>
#include "colorGenerator.h"
#include "RGBPixel.h"
#include "globals.h"
#include "Arduino.h"
unsigned long millis();
typedef std::list<colorGenerator> generatorList;
class colorController
{
public:
virtual bool refresh();
protected:
generatorList generators;
};
#endif //_COLORCONTROLLER_H
As you can see, the controller has a list of colorGenerators and method to refresh them all (called from loop()), which unless overridden in the child class, does this:
bool colorController::refresh()
{
for (generatorList::iterator it = generators.begin(); it != generators.end(); ++it)
it->refresh();
bool dirty = false;
for (int i = NUM_OF_LEDS-1; i >= 0; --i)
dirty |= RGBPixels[i].refresh();
return dirty;
}
The CC_Cascade class (derived from colorController) sets things up like this:
CC_Cascade.h
#ifndef _CC_CASCADE_H
#define _CC_CASCADE_H
#include "colorController.h"
class CC_Cascade : public colorController
{
public:
CC_Cascade();
~CC_Cascade();
};
#endif //_CC_CASCADE_H
CC_Cascade.cpp
#include "CC_Cascade.h"
#include "CG_EmeraldWaters.h"
CC_Cascade::CC_Cascade()
{
colorGenerator * freshBubblingSpring = new CG_EmeraldWaters();
generators.push_back(*freshBubblingSpring);
RGBPixels[0].setParent(freshBubblingSpring);
RGBPixels[0].setDelay(40);
for (int i = 1; i < NUM_OF_LEDS; ++i)
{
RGBPixels[i].setParent(&RGBPixels[i-1]);
RGBPixels[i].setDelay(500-(9*i)); //FIXME: magic number only works for 50ish pixels
}
}
CC_Cascade::~CC_Cascade()
{
//TODO: delete generators
}
So far so clear?
Let me draw your attention to the colorController::refresh() function. What should happen is that every time it's called, there's one colorGenerator in the generators list (because the CC_Cascade constructor put it there), which is a CG_EmeraldWaters. When refresh() is called on this (through the iterator), it calls colorGenerator::refresh(), which in turn calls updateColor(). In the case of CG_EmeraldWaters, this is overriden, so CG_EmeraldWaters::updateColor SHOULD be called, giving a turquoise colour. Using some serial write statements to debug, I can see that IN FACT colorGenerator::updateColor() is called, so in that case I'd expect an orangey colour, BUT neither of these is affecting the colour of the pixels, which are all staying a purple colour as set in the CG_EmeraldWaters contructor.
Doing a little messing about, I added the following line to colorGenerator::updateColor(): RGBPixels[0].setColor(255,127,0);
Rather than the orange colour I was hoping for, the first pixel alternated quickly between purple and orange, suggesting (IMHO) that my new line of code was doing its job, but then the pixel was pulling its original purple colour again from the colorGenerator, and that somehow colorGenerator::updateColor() doesn't change the colour of the colorGenerator (given that I don't get a compile error, what IS it changing?).
So my qustions are: (QUESTIONSHERE)
1) How can I change the value of colorSource::currentR(/G/B) from within colorGenerator::updateColor(), given that currentR(/G/B) is declared as protected in colorSource and that colorGenerator is directly derived from colorSource?
2) Given an instance of CG_EmeraldWaters, how can I call CG_EmeraldWaters::updateColor() via colorGenerator::refresh(), which CG_EmeraldWaters inherits, given that updateColor() is declared as virtual in colorGenerator and overriden in CG_EmeraldWaters?
Below is the code of colorGenerator and CG_EmeraldWaters:
colorSource.h:
#ifndef _COLORSOURCE_H
#define _COLORSOURCE_H
#include "Arduino.h"
#ifdef DEBUG
#include "colorGenerator.h" //FIXME: delete Me
#endif
//#define byte unsigned char
typedef byte colorStorage_t;
class colorSource
{
public:
colorSource();
colorSource(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB);
void setColor(colorStorage_t newR, colorStorage_t newG, colorStorage_t newB);
//TODO: better implementation than this
colorStorage_t getR();
colorStorage_t getG();
colorStorage_t getB();
bool hasChanged();
protected:
colorStorage_t currentR;
colorStorage_t currentG;
colorStorage_t currentB;
bool dirty;
#ifdef DEBUG
friend colorGenerator; //FIXME: delete Me
#endif
};
#endif //_COLORSOURCE_H
colorSource.cpp:
#include "colorSource.h"
colorSource::colorSource()
{
//nothing here
}
colorSource::colorSource(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB)
:
currentR(initialR),
currentG(initialG),
currentB(initialB)
{
//intialised in the list
Serial.println("Constructed Color Source with initial color");
}
void colorSource::setColor(colorStorage_t newR, colorStorage_t newG, colorStorage_t newB)
{
currentR = newR;
currentG = newG;
currentB = newB;
}
colorStorage_t colorSource::getR()
{
return currentR;
}
colorStorage_t colorSource::getG()
{
return currentG;
}
colorStorage_t colorSource::getB()
{
return currentB;
}
bool colorSource::hasChanged()
{
return !dirty;
}
colorGenerator.h:
#ifndef _COLORGENERATOR_H
#define _COLORGENERATOR_H
#include "colorSource.h"
#ifdef DEBUG
#include "RGBPixel.h" //delete me, used for debugging!
#include "globals.h" //and me!
#endif
extern "C" unsigned long millis();
class colorGenerator : public colorSource
{
public:
colorGenerator(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB);
bool refresh();
protected:
virtual void updateColor();
unsigned long nextColorUpdate = 0;
unsigned short delay = 40;
};
#endif //_COLORGENERATOR_H
colorGenerator.cpp:
#include "Arduino.h"
#include "colorGenerator.h"
colorGenerator::colorGenerator(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB)
:
colorSource(initialR,initialG,initialB)
{
//intialised in the list
//Serial.println("Constructed Color Generator");
}
bool colorGenerator::refresh()
{
#ifdef DEBUG
Serial.print("colorGenerator::refresh()");
#endif
if (millis() < nextColorUpdate)
return false;
nextColorUpdate = millis() + (unsigned long) delay;
this->updateColor();
return true;
}
void colorGenerator::updateColor() //this function gets called (even if it has been overridden in a child class), but the code in it doesn't have the desired effect
{
#ifdef DEBUG
//Serial.print("colorGenerator::updateColor()");
//RGBPixels[0].setColor(255,127,0);
#endif
currentR = random(127,255);
currentG = random(0,127);
currentB = 0;
}
CG_EmeraldWaters.h:
#ifndef _CG_EMERALDWATERS_H
#define _CG_EMERALDWATERS_H
#include "colorGenerator.h"
#include "globals.h"
#include "RGBPixel.h"
class CG_EmeraldWaters : public colorGenerator
{
public:
CG_EmeraldWaters();
protected:
void updateColor();
};
#endif //_CG_EMERALDWATERS_H
CG_EmeraldWaters.cpp:
#include "Arduino.h"
#include "CG_EmeraldWaters.h"
CG_EmeraldWaters::CG_EmeraldWaters()
:
colorGenerator(255,0,255) //this color seems to stick! Changes made by updateColor() aren't propogated to the pixels.
{
//initialised in list
//Serial.println("Constructed Emerald Waters");
}
long random(long,long);
void CG_EmeraldWaters::updateColor() //this never seems to be called!
{
currentR = 0;
currentG = random(0,255);
currentB = random(0,255);
}
And finally, the main sketch file:
#include "FastSPI_LED2.h"
#include <StandardCplusplus.h>
#include "colorController.h"
#include "RGBPixel.h"
#include "globals.h"
#include "CC_Cascade.h"
colorController * currentColorController;
RGBPixel RGBPixels[NUM_OF_LEDS];
struct CRGB ledString[NUM_OF_LEDS];
void setup()
{
#ifdef DEBUG
//debugging:
Serial.begin(9600);
Serial.println("In Setup");
#endif
// sanity check delay - allows reprogramming if accidently blowing power w/leds
//delay(2000);
LEDS.setBrightness(8);
LEDS.addLeds<WS2801>(ledString, NUM_OF_LEDS);
currentColorController = new CC_Cascade();
}
void writeValuesToString()
{
for (int i = 0; i < NUM_OF_LEDS; ++i)
ledString[i] = CRGB(RGBPixels[i].getR(),RGBPixels[i].getG(),RGBPixels[i].getB());
LEDS.show();
}
void loop()
{
static bool dirty = false; //indicates whether pixel values have changed since last hardware write
//unsigned long lastHardwareWrite = 0; //time of last hardware write - only do this once per milisecond to avoid flicker (this method doesn't work, still flickers)
dirty |= currentColorController->refresh();
if (dirty)
{
dirty = false;
writeValuesToString();
delay(1); //to prevent flicker
}
}
Your problem is due to the so-called object slicing. Here is what is going on: when you declare a list of type generatorList
typedef std::list<colorGenerator> generatorList;
its members are restricted to what is in colorGenerator. Nothing from the derived class matters, so when you push
colorGenerator * freshBubblingSpring = new CG_EmeraldWaters();
generators.push_back(*freshBubblingSpring);
the CG_EmeraldWaters part that is not also in colorGenerator gets "sliced off"; you end up with a version of colorGenerator.
The reason for this is described in the wikipedia article linked above. To fix this problem, change the list to contain pointers, preferably smart pointers, pointing to colorGenerator instances. Then the slicing problem will no longer be relevant:
typedef std::list<unique_ptr<colorGenerator> > generatorList;
...
unique_ptr<colorGenerator> freshBubblingSpring(new CG_EmeraldWaters());
generators.push_back(freshBubblingSpring);
You should be able to call the base class's private and protected methods from the derived class, unless I'm missing something.
To call an overidden method (e.g. virtual foo() is defined in class Base and overridden in class Derived), you can access the Base method by calling derivedObj.Base::foo() in your code.