I am trying to create a program that has the user click twice on the screen and a rectangle is drawn according to what was clicked.
Right now all I am trying to do is set my classes up to be able to correctly draw a rectangle manually without worrying about where the user clicks.
Eventually my program will be able to draw stuff like circles and triangles so I decided to use Polymorphism and have each shape type (i.e. Rectangle) be its own class that inherits from a class called Shapes.
I then have a class called Game which holds a Shapes object.
Shapes.h
#ifndef _shapes_h_
#define _shapes_h_
#include <vector>
#include "glut.h"
class Shapes
{
public:
void DrawAll() const;
void Add(Shapes * shape);
virtual void Draw() const {}
protected:
std::vector<Shapes *> mShapes;
};
#endif
Shapes.cpp
#include "Shapes.h"
#include <iostream>
void Shapes::DrawAll() const
{
int i;
for (i = 0; i < mShapes.size(); i++)
{
mShapes[i]->Draw();
}
}
void Shapes::Add(Shapes * shape)
{
mShapes.push_back(shape);
}
Rectangle.h
#ifndef _rectangle_h_
#define _rectangle_h_
#include "Shapes.h"
class Rectangle : public Shapes
{
public:
Rectangle(std::vector<int> p1, std::vector<int> p2);
void Draw() const;
private:
std::vector<int> mP1;
std::vector<int> mP2;
};
#endif
Rectangle.cpp
#include "Rectangle.h"
#include <iostream>
Rectangle::Rectangle(std::vector<int> p1, std::vector<int> p2)
{
mP1 = p1;
mP2 = p2;
}
void Rectangle::Draw() const
{
std::cout << "Draw Me " << std::endl;
glColor3d(0, 0, 0);
glBegin(GL_QUADS);
glVertex2d(mP1[0], mP1[1]);
glVertex2d(mP2[0], mP1[1]);
glVertex2d(mP2[0], mP2[1]);
glVertex2d(mP1[0], mP2[1]);
glEnd();
}
Game.h
#ifndef _game_h_
#define _game_h_
#include <vector>
#include "Shapes.h"
class Game
{
public:
void Click(int x, int y);
void Draw();
private:
Shapes mTest;
};
#endif
The first Game.cpp below is coded in a way of what I am trying to do, but it throws me the error Unhandled exception at 0x001AF742 in Shapes.exe: 0xC0000005: Access violation reading location 0x00000001. After looking into this, I've found that some __vfptr hidden pointer variable (that I think controls virtual stuff) gets set to 0 and causes memory issues.
Note, Click() only gets called when the mouse is pressed, Draw() is called anytime any type of event happens (e.i. mouse press, mouse release, key press, key release etc.) When the mouse is pressed, both events get called, but Click() gets called first.
Also, mTestis the variable that is the Shapes object.
Game.cpp: Doesn't Work
#include "Game.h"
#include "Rectangle.h"
#include <iostream>
void Game::Click(int x, int y)
{
std::vector<int> p1;
p1.push_back(200);
p1.push_back(200);
std::vector<int> p2;
p2.push_back(250);
p2.push_back(250);
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
}
void Game::Draw()
{
mTest.DrawAll();
}
However, what seems to baffle me is if I add a Shape Rectangle to mTest inside of the Draw() function right before I call DrawAll(), it works. However, I want to be able to create the Rectangle depending on where the User clicks, and this method wont allow that.
Game.cpp: Works
#include "Game.h"
#include "Rectangle.h"
#include <iostream>
void Game::Click(int x, int y)
{
}
void Game::Draw()
{
std::vector<int> p1;
p1.push_back(200);
p1.push_back(200);
std::vector<int> p2;
p2.push_back(250);
p2.push_back(250);
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
mTest.DrawAll();
}
In Shapes class replace
std::vector<Shapes *> mShapes;
by
std::vector<std::shared_pointer<Shapes>> mShapes;
Than replace code
Rectangle rect(rp1, rp2);
Shapes * rectangle = ▭
mTest.Add(rectangle);
by
mTest.Add(std::make_shared<Rectangle>(rp1, rp2));
And finally replace method definition
void Shapes::Add(Shapes * shape)
by
void Shapes::Add(std::shared_ptr<Shapes> shape)
It makes your code works.
Summary: If you need pointers, think about smart pointers (std::unique_ptr mentioned by #user657267 is smart pointer too). You can read about smart pointers in many places, here and here. For better design, do not forget for design patterns.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
i saw a few posts with same problem but i didn't not manage to understand how do i make the temporary object to constant
Map.H
#ifndef _Map_
#define _Map_
class Map
{
private:
int Board[7][7];
public:
Map();
Map(int mapNum);
~Map();
void print() const;
};
#endif
Map.Cpp basicly just creates a 7*7 array with 0 or 1 in all places
Robots.H
#ifndef _Robot_
#define _Robot_
#include "Map.h"
class Robot
{
private:
int _RobotID;
int _mapNum;
int _X;
int _Y;
public:
Robot();
~Robot();
Robot (int mapNum, int Line, int Column);
void setRobotID(int newid);
void print() const;
};
#endif
s
Robot.cpp
#include "Robot.h"
#include "Map.h"
#include <iostream>
#include "Game.h"
using namespace std;
Robot::Robot()
{
}
Robot::Robot(int mapNum, int line, int column) {
_mapNum = mapNum;
_X = line;
_Y = column;
_RobotID=0;
}
now creating a map in my main works and so does printing it.
same goes for robot.
what i want to do is connect the robot and the map inside my "game.cpp\game.h" so that each robot that i add will check in the map (double array with 0's or 1's )if it has a 1 it wont add it to map. and if it has a 0 it will.
(addRobot function is suppose to do that)
Game.H
#ifndef _Game_
#define _Game_
#include <vector>
#include <iostream>
#include "Map.h"
#include "Robot.h"
class Game
{
private:
static int _RobotsNum;
Map map1;
Map map2;
public:
void AddRobot(int mapnum, int x, int y);
Map getMap(int mapnum);
Game();
~Game();
};
#endif
Game cpp
#include "Game.h"
#include <algorithm>
#include <vector>
using namespace std;
int Game::_RobotsNum = 0;
vector <Robot> RobotVec;
Game::Game()
: map1(1),
map2(2)
{
}
Game::~Game()
{
}
void Game::AddRobot(int mapnum, int x, int y) {
my main
int main() {
Game game;
// Game* pgame = new Game();
game.AddRobot(1, 3, 4);
game.AddRobot(1, 4, 4);
game.AddRobot(1, 5, 4);
hope you guys can help me. thanks
This constructor has three local variables with the same names as other variables:
Game::Game()
{
vector <Robot> RobotVec; // Not your global variable
Map map1(1); // Not your member variable
Map map2(2); // Not your member variable either
}
In order to initialise members, you use the initialiser list:
Game::Game()
: map1(1),
map2(2)
{
}
In addRobot, this creates a robot and points X at it:
Robot* X = new Robot;
This also creates a robot, so now you have two:
Robot newRobot(mapnum, x, y);
And this memory leak points X away from its original robot and instead points it at newRobot, which will be destroyed immediately afterwards:
X = &newRobot;
Note that addRobot does not at any point add either robot to anything – it creates two and ignores them both.
You should make the vector a member (avoid global variables unless repeating other people's mistakes is a particular passion of yours):
class Game
{
private:
int robotsNum;
vector<Robot> robotVec;
Map map1;
Map map2;
// ...
};
Game::Game()
: robotsNum(0),
map1(1),
map2(2)
{
}
And add your new robot to the vector:
void Game::AddRobot(int mapnum, int x, int y) {
// ...
Robot newRobot(mapnum, x, y);
robotsNum++;
newRobot.setRobotID(robotsNum);
robotVec.push_back(newRobot);
}
Robot newRobot(mapnum, x, y);
This creates an object of type Robot named newRobot. At the end of the block where it was created it will be destroyed.
I was tasked to debug a code that was meant to draw a simple polygon out of 4 points using FLTK. The MyWindow class derive from Fl_Window. The Shape class is the parent class for ClosedPolyline. Both MyWindow and Shape hold a vector to draw all of the shapes.
The problem is that after compiling and run, win.show() opens an empty window without any drawing. I'm puzzled to understand this behavior.
Here is the code (I've omitted some of the parts that are not related to drawing ClosedPolyline):
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Draw.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Device.H>
#include <initializer_list>
#include <vector>
#include <functional>
//#include <cmath>
//#include <math.h>
struct Point {
int x,y;
Point(int xx, int yy) : x(xx), y(yy) { }
};
class Shape{
public:
Point point(int idx) const {
return (points[idx]);
}
unsigned int points_size() const {
return points.size();}
void draw() /*const*/{
draw_lines();
}
void add(Point p){ points.push_back(p); }
protected:
virtual void draw_lines() {}
private:
std::vector<Point> points;
};
class ClosedPolyline: public Shape {
public:
/*ClosedPolyline(std::initializer_list<Point> pp) {
if (pp.size() > 0) {
for (Point p: pp)
add(p);
}
}
*/
ClosedPolyline(Point a1, Point a2, Point a3, Point a4){
add(a1); add(a2); add(a3); add(a4);
}
protected:
void draw_lines() override{
for (unsigned int i=1; i<points_size(); ++i){
fl_line(point(i-1).x, point(i-1).y, point(i).x, point(i).y);
}
}
};
class MyWindow: public Fl_Window {
public:
MyWindow(int x, int y, int w, int h, const char* title = 0)
: Fl_Window(x, y, w, h, title) {}
void Attach(Shape s) {
shapes.push_back(&s);
}
//void draw_shapes(){draw();}
protected:
void draw() override{
for(Shape * s: shapes) {
s->draw();
//s.draw();
}
}
private:
std::vector<Shape*> shapes;
};
And here is the main() function:
int main() {
MyWindow win(100, 100, 600, 400, "C++ Test task");
ClosedPolyline p{Point{100, 100}, Point{100, 200}, Point{500, 100}, Point{500, 200}};
win.Attach(p);
win.end();
win.show();
return (Fl::run());
}
Lets take a look at your MyWindow::Attach function:
void Attach(Shape s) {
shapes.push_back(&s);
}
In the function, the argument s is passed by value. That means it's the same as a local variable inside the function. And as such it will go out of scope and be destructed once the function return.
Saving a pointer to that variable will lead to you saving a stray pointer, pointing to a non-existing object. Dereferencing that pointer will lead to undefined behavior, turning your whole program ill-formed and invalid.
One way to solve the problem is to make sure that the object don't go out of scope. This can be done by using smart pointers like e.g. std::unique_ptr. And to use it from the beginning already when you define the variable p in the main function.
Another way to solve your problem is to assume that the Shape passed to Attach will have a lifetime that outlives the Shape object, and you could therefore pass the Shape by reference:
void Attach(Shape& s) {
shapes.push_back(&s);
}
Now you no longer get a copy of the Shape object, and push a pointer to the original object (in your case the object p in the main function). Dereferencing the pointer will be valid as long as the original object is alive and in scope.
I try run that code in VS2015 and get a lot of error( of course fix attach window pass by reference ) But when I run to linux , it can draw, So I think you should move to linux.
Before I start, I'm going to apologize ahead of time for any seemingly obvious mistakes I may have made. I'm pretty in over my head at this point and there's probably quite a few errors in here.
Any suggestions on fixing what I have, or better ways of setting up what I want are appreciated.
I have two classes, the Renderer and the FParticle.
What I want is for the FParticle constructor to pass a pointer of itself to the Renderer. The Renderer will store the various FParticle pointers in a vector and then when DrawObjects() is called, it will draw all of the objects using the list of pointers.
This way I don't have to worry about passing each particle into the renderer each step of the game loop, and can instead just draw them from the list of pointers.
The problem is that the program is segfaulting and I can't figure out how to deal with it.
The segfault occurs in renderer.cpp
The files are here:
renderer.h
#pragma once
#ifndef RENDERER_H
#define RENDERER_H
#include <SFML/Graphics.hpp>
#include <vector>
class FParticle;
class Renderer {
private:
std::vector<const FParticle*> object_buffer_;
sf::RectangleShape rectangle_;
public:
Renderer();
void addObject(const FParticle &object);
void drawObjects(sf::RenderWindow &window);
};
#endif // RENDERER_H
renderer.cpp
#include "renderer.h"
#include "fparticle.h"
#include <iostream>
Renderer::Renderer() {}
void Renderer::addObject(const FParticle &object)
{
object_buffer_.push_back(&object);
}
void Renderer::drawObjects(sf::RenderWindow &window)
{
for (int i = object_buffer_.size(); i > 0; i--)
{
rectangle_.setSize(object_buffer_[i]->get_size()); // <------- SEGFAULT HERE
rectangle_.setPosition(object_buffer_[i]->get_position());
rectangle_.setFillColor(sf::Color::White);
std::cout << object_buffer_[i]->get_size().x << std::endl;
window.draw(rectangle_);
}
}
fparticle.h
#pragma once
#ifndef FPARTICLE_H
#define FPARTICLE_H
#include <SFML/Graphics.hpp>
class Renderer;
class FParticle
{
protected:
sf::Vector2f size_;
sf::Vector2f position_;
sf::Vector2f velocity_;
sf::Vector2f acceleration_;
float inverse_mass_;
float damping_;
public:
FParticle(Renderer &picasso);
sf::Vector2f get_size() const;
sf::Vector2f get_position() const;
void set_mass();
void set_inverse_mass();
};
#endif // FPARTICLE_H
fparticle.cpp
#include "fparticle.h"
#include "renderer.h"
#include <iostream>
FParticle::FParticle(Renderer &picasso)
{
size_.x = 5.f;
size_.y = 5.f;
position_.x = 10.f;
position_.y = 10.f;
picasso.addObject(*this);
}
sf::Vector2f FParticle::get_size() const
{
return size_;
}
sf::Vector2f FParticle::get_position() const
{
return position_;
}
pseudo main.cpp
int main()
{
Renderer picasso;
FParticle p1(picasso);
while(gamestate != Exiting)
{
window.clear(Black);
picasso.drawObjects(window_);
window.display();
}
return 0
}
Like I said, I'm relatively in over my head and am still in the early stages of learning. Any suggestions or advice on anything are appreciated.
Your vector is only indexible from 0... size-1. You're starting at size, thus out of range, thus invoking undefined behavior, thus (because you were actually fortunate) your crash.
Use an iterator for your collection. If you want this in reverse, use a reverse-iterator.
for (auto it = object_buffer.rbegin(); it != object_buffer.rend(); ++it)
{
rectangle_.setSize((*it)->get_size());
rectangle_.setPosition((*it)->get_position());
rectangle_.setFillColor(sf::Color::White);
std::cout << (*it)->get_size().x << std::endl;
window.draw(rectangle_);
}
or something to that effect.
Note: When in doubt, replace vector/deque operator[i] usage with obj.at(i) accessors instead. The latter is range-checked and will bark at you via assertion the moment you pass an invalid-ranged index.
Best of luck.
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.
Intro:
In my program, a group object has an std::vector full of polygons (a ring and holes) and a polygon object has an std::vector of points. In reality, the classes are more complicated, I've stripped them down here to illustrate my problem.
The problem:
I want to be able to modify the point's x and y coordinates from within it's corresponding group object. Below, in group.cpp, I have a dummy function called void Group::tryChangingAllX() that tries to accomplish this. However, calling show() on the group afterwards shows no change to it's polygon's point's coordinates.
I think I need to use references/pointers, but I need a nudge in the right direction.
point.cpp:
#include "point.h"
#include <iostream>
Point::~Point(){}
Point::Point(int x, int y){
_x = x;
_y = y;
}
void Point::show(){std::cout << "(" << x() << "," << y() << ")";}
void Point::x(int x){_x = x;}
void Point::y(int y){_y = y;}
int Point::x(){return _x;}
int Point::y(){return _y;}
point.h:
#ifndef POINT_GUARD
#define POINT_GUARD
class Point{
int _x;
int _y;
public:
Point(int x, int y);
~Point();
void show();
int x();
int y();
void x(int x);
void y(int y);
};
#endif
polygon.cpp:
#include "polygon.h"
#include "point.h"
#include <iostream>
#include <vector>
Polygon::~Polygon(){}
Polygon::Polygon(){}
std::vector<Point> Polygon::points(){return _points;}
Polygon::Polygon(std::vector<Point> points){_points = points;}
void Polygon::show(){
std::cout << "Points: ";
for(std::vector<Point>::size_type i = 0; i != _points.size(); i++) {
_points[i].show();
}
}
polygon.h:
#ifndef POLYGON_GUARD
#define POLYGON_GUARD
#include <vector>
#include "point.h"
class Polygon{
//private:
std::vector<Point> _points;
public:
~Polygon();
Polygon ();
Polygon(std::vector<Point> points);
std::vector<Point> points();
void show();
};
#endif
group.cpp:
#include <iostream>
#include <vector>
#include "group.h"
#include "polygon.h"
Group::~Group(){}
Group::Group(std::vector<Polygon> polygons){
_ring = polygons.front();
polygons.erase(polygons.begin());
_holes = polygons;
}
void Group::tryChangingAllX(){
std::vector<Point> points = _ring.points();
for(std::vector<Point>::size_type i = 0; i != points.size(); i++) {
points[i].x(15);
}
}
void Group::show(){
_ring.show();
if(_holes.size()>0){
for(std::vector<Polygon>::size_type i = 0; i != _holes.size(); i++) {
_holes[i].show();
}
}
}
group.h:
#ifndef GROUP_GUARD
#define GROUP_GUARD
#include <vector>
#include "polygon.h"
class Group{
Polygon _ring;
std::vector<Polygon> _holes;
public:
~Group();
Group(std::vector<Polygon> polygons);
void show();
void tryChangingAllX();
};
#endif
Thanks!
The function
std::vector<Point> points();
returns by value, so when you call it, you get a copy of the member. You need to change it to
std::vector<Point>& points();
After you've done this
std::vector<Point> points = _ring.points();
also makes a copy of the returned value. To refer to the actual member in _ring, change to:
std::vector<Point>& points = _ring.points();
That should do it.
Note that you should pass std::vector by const reference to prevent an un-necessary copy:
Polygon(const std::vector<Point>& points);
and consider making methods that don't modify the class const:
int x() const;
This is exactly your problem - you're getting a copy of your points rather than working on a reference to the original points themselves.
polygon.cpp:
return points by reference not value:
std::vector<Point>& Polygon::points(){return _points;} // note the '&' in the return
group.cpp:
obtain a reference to the points, not a copy
std::vector<Point>& points = _ring.points(); // note the '&' in what you're getting
Answers posted by Luchian and lori are technically correct. But there are design considerations that I want to point out.
Returning a reference will allow anyone to modify private parts of Polygon object. By design you only want Group class to do this. Consider making Group a friend of Polygon. Group then will have access to private bits of Polygon. This will ensure a tighter encapsulation overall.
In polygon.h
friend class Group;
In group.cpp
void Group::tryChangingAllX()
{
for(std::vector<Point>::size_type i = 0; i != _ring._points.size(); i++)
{
_ring._points[i].x(15);
}
}