Accessing an array in one class from another class with C++ - c++

I'm having trouble trying to access an array used in my main class from another class. My application is an editor for making a 2d platform game - it basically allows you to place down 2D assets (segments) and build up a level.
My main class handles an array of map segment classes (each segment class in the array holds information such as position, scale and rotation of the segment on the map) and draws them to screen.
I have a separate class which is basically a panel (dragabble, and resizable like you would find in something like Photoshop) that is initialised in the main class and is used to draw a grid of available segments from a file. What I need is the ability to click on one of the segments which then adds information to the array that is referenced in the main class.
I have my main class "Map" which declares an array:
map.h (simplified)
class Map
{
public:
MapSegment* mapSeg[512];
};
I'm then trying to send a reference of that array when I create the panel to display the available segments, like so:
Panel* segmentPane = new SegmentPanel(sf::Rect<float>(200,200,250,200), mapSeg);
Segment Panel header is formed as follows:
class SegmentPanel : public Panel
{
public:
SegmentPanel(sf::Rect<float> _position, MapSegment* mapSeg[512];);
void Update();
void Draw(sf::RenderWindow & renderWindow);
void ReadSegments();
private:
std::vector<SegmentDefinition *> segDef;
MapSegment* mapSeg[512];
};
And SegmentPanel cpp:
SegmentPanel::SegmentPanel(sf::Rect<float> _position, MapSegment* mapSeg[512])
: Panel(_position)
{
panelTitle = "Segment Selection";
}
void SegmentPanel::Update()
{
// Update segments
}
void SegmentPanel::Draw(sf::RenderWindow & renderWindow)
{
// Draw default panel items
Panel::Draw(renderWindow);
// Draw segments
}
However, add elements to the array from SegmentPanel.cpp class doesn't seem to be reflected in my main Main class - it seems to create a new array in memory.
I'm still fairly new to C++ after working with C#!

First, there's no such thing as an array parameter type in C++. In your SegmentPanel constructor, the MapSegment* mapSeg[512] parameter is actually equivalent to MapSegment** mapSeg; it's just a pointer to a pointer!
Panel* segmentPane = new SegmentPanel(sf::Rect<float>(200,200,250,200), mapSeg);
Here, you attempt to pass the array mapSeg. This undergoes array-to-pointer conversion which turns it into a pointer to its first element (a MapSegment**) and then passes that pointer.
This is all fine, but you do nothing with the mapSeg argument in your constructor. If you want access to the array, you'll need to store that pointer somewhere. You can do that by changing the member of SegmentPanel called mapSeg to:
MapSegment** mapSeg;
Then change your constructor to:
SegmentPanel::SegmentPanel(sf::Rect<float> _position, MapSegment** mapSeg)
: Panel(_position), mapSeg(mapSeg)
{
panelTitle = "Segment Selection";
}
Note the initialisation of mapSeg in the member initialization list.
Another way you can do this is to take a reference to array type argument instead. Your constructor would now look like:
SegmentPanel::SegmentPanel(sf::Rect<float> _position, MapSegment* (&mapSeg)[512])
: Panel(_position), mapSeg(mapSeg)
{
panelTitle = "Segment Selection";
}
The type of the mapSeg argument is a "reference to array of 512 pointers to MapSegment". You'll then need to make the member mapSeg the same type.

Related

store list of objects in class

Brand new to c++, trying to figure out how to create a class that I can store a list of objects in.
I have a surface class with subclasses such as triangles, circles, ect.
I'm trying to create a class called Scene, that I can store a list of all the surfaces.
Here's the header file for what I'm trying to do. How do you do this in c++?
class Scene
{
private:
//background color elements
float bgRed;
float bgGreen;
float bgBlue;
//array of different surfaces
Surface surfaces[]; //<--- What I want
public:
Scene();
addSurface(Surface s);
};
There are many possibilities, here's a easy one with a std::vector:
vector<Surface> surfaces;
...
addSurface(const Surface &s) //const and & are not strictly necessary, but better
{
surfaces.push_back(s);
}
...
//accessing like an array: surfaces[index]
//element count: surfaces.size()
This copies the passed objects (s) while inserting. If you want the same object, so that changes in the vector affect the object "outside" too (and vice-versa), you'll need an additional pointer.
Also note that copying of an child class object of Surface will result in a pure Surface, without the child class part (object slicing). If you need that part, you'll need a pointer too (if you don't have one already).
//pointer variant
vector<Surface*> surfaces;
...
addSurface(Surface &s)
{
surfaces.push_back(&s);
}

How to store objects of different class in an array of pointers

I have 3 classes. DrawGameComp' and 'GameComp' where 'GameComp' is the base class of 'DrawGameComp'. I have an array of pointers in Game class which is the controlling class. '
GameComp * components[]; From the main I have to create a dynamic instance of Game and store add new objects of GameComp and DrawGameComp to the array of pointers of type GameComp.
Game Game1(2);
Game1.Add(new GameComponent);
Game1.Add(new DrawableGameComponent);
I'v done this part in the main. Because from the main I have to invoke Add passing object as the parameter. When i store these objects I also want assign an id of 1 to the first object and an id of 2 to the second object. How can i include that too.
The Add() function of my Game class is as follows
void Game::Add(GameComponent*)
{
components[0]=GameComp;
componentCount++;
}
but it give me error. I have tried so hard. But I couldn't. Also how do I invoke the Display() member function of these objects in the Array? is it this way?
components[0]->Display();
The Add method should look like:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
Make sure you zero out componentCount in the constructor.
Using the array:
components[i]->DoSomething();
1) You probably meant to write the following:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
2) components[0]->Display() will work, if display is a member function of GameComponent class.

Creating a new object by calling the new constructor with a string

I was recently in a job interview and my interviewer gave me a modeling question that involved serialization of different shapes into a file.
The task was to implements shapes like circle or rectangles by first defining an abstract class named Shape and then implements the various shapes (circle, rectangle..) by inheriting from the base class (Shape).
The two abstract methods for each shape were: read_to_file (which was supposed to read the shape from a file) and write_to_file which supposed to write the shape into a file.
All was done by the implementation of that virtual function in the inherited shape (Example: For Circle I was writing the radius, for square I saved the side of the square....).
class Shape {
public:
string Shape_type;
virtual void write_into_file()=0;
virtual void read_into_files()=0;
Shape() {
}
virtual ~Shape() {
}};
class Square: public Shape {
public:
int size;
Square(int size) {
this->size = size;
}
void write_into_file() {
//write this Square into a file
}
void read_into_files() {
//read this Square into a file
}
};
That was done in order to see if I know polymorphism.
But, then I was asked to implement two functions that take a vector of *shape and write/read it into a file.
The writing part was easy and goes something like that:
for (Shape sh : Shapes) {
s.write_into_file();
}
as for the reading part I thought about reading the first word in the text (I implemented the serializable file like a text file that have this line: Shape_type: Circle, Radius: 12; Shape_type:Square...., so the first words said the shape type). and saving it to a string such as:
string shape_type;
shape_type="Circle";
Then I needed to create a new instance of that specific shape and I thought about something like a big switch
<pre><code>
switch(shape_type):
{
case Circle: return new circle;
case Square: return new square
......
}
</pre></code>
And then, the interviewer told me that there is a problem with this implementation
which I thought was the fact that every new shape the we will add in the future we should also update int that big swicht. he try to direct me into a design pattern, I told him that maybe the factory design pattern will help but I couldn't find a way to get rid of that switch. even if I will move the switch from the function into a FactoryClass I will still have to use the switch in order to check the type of the shape (according to the string content i got from the text file).
I had a string that I read from the file, that say the current type of the shape. I wanted to do something like:
string shape_type;
shape_type="Circle";
Shape s = new shape_type; //which will be like: Shape s = new Circle
But I can't do it in c++.
Any idea on what I should have done?
In you factory you could map a std::string to a function<Shape*()>. At startup you register factory methods will the factory:
shapeFactory.add("circle", []{new Circle;});
shapeFactory.add("square", []{new Square;});
shapeFactory.add("triangle", []{new Triangle;});
In your deserialization code you read the name of the type and get its factory method from the factory:
std::string className = // read string from serialization stream
auto factory = shapeFactory.get(className);
Shape *shape = factory();
You've now got a pointer to the concrete shape instance which can be used to deserialize the object.
EDIT: Added more code as requested:
class ShapeFactory
{
private:
std::map<std::string, std::function<Shape*()> > m_Functions;
public:
void add(const std::string &name, std::function<Share*()> creator)
{
m_Functions.insert(name, creator)
}
std::function<Shape*()> get(const std::string &name) const
{
return m_Functions.at(name);
}
};
NOTE: I've left out error checking.
In C++, with
for (Shape sh : Shapes) {
s.write_into_file();
}
you have object slicing. The object sh is a Shape and nothing else, it looses all inheritance information.
You either need to store references (not possible to store in a standard collection) or pointers, and use that when looping.
In C++ you would to read and write some kind of type tag into the file to remember the concrete type.
A virtual method like ShapeType get_type_tag() would do it, where the return type is an enumeration corresponding to one of the concrete classes.
Thinking about it, though, the question was probably just getting at wanting you to add read and write functions to the interface.
You could create a dictionary of factory functions keyed by a shape name or shape id (shape_type).
// prefer std::shared_ptr or std::unique_ptr of course
std::map<std::string, std::function<Shape *()>> Shape_Factory_Map;
// some kind of type registration is now needed
// to build the map of functions
RegisterShape(std::string, std::function<Shape *()>);
// or some kind of
BuildShapeFactoryMap();
// then instead of your switch you would simply
//call the appropriate function in the map
Shape * myShape = Shape_Factory_Map[shape_type]();
In this case though you still have to update the creation of the map with any new shapes you come up with later, so I can't say for sure that it buys you all that much.
All the answers so far still appear to have to use a switch or map somewhere to know which class to use to create the different types of shapes. If you need to add another type, you would have to modify the code and recompile.
Perhaps using the Chain of Responsibility Pattern is a better approach. This way you can dynamically add new creation techniques or add them at compile time without modifying any already existing code:
Your chain will keep a linked list of all the creation types and will traverse the list until it finds the instance that can make the specified type.
class Creator{
Creator*next; // 1. "next" pointer in the base class
public:
Creator()
{
next = 0;
}
void setNext(Creator*n)
{
next = n;
}
void add(Creator*n)
{
if (next)
next->add(n);
else
next = n;
}
// 2. The "chain" method in the Creator class always delegates to the next obj
virtual Shape handle(string type)
{
next->handle(i);
}
);
Each subclass of Creator will check if it can make the type and return it if it can, or delegate to the next in the chain.
I did create a Factory in C++ some time ago in which a class automatically registers itself at compile time when it extends a given template.
Available here: https://gist.github.com/sacko87/3359911.
I am not too sure how people react to links outside of SO but it is a couple of files worth. However once the work is done, using the example within that link, all that you need to do to have a new object included into the factory would be to extend the BaseImpl class and have a static string "Name" field (see main.cpp). The template then registers the string and type into the map automatically. Allowing you to call:
Base *base = BaseFactory::Create("Circle");
You can of course replace Base for Shape.

How can an object of a vector access the vector elements

This is a program that simulates a simple resource gathering game
The robots gather resources from the map and move around randomly each one doing some actions.
My problem is that i want to access a vector from class map within the derivered class of robots "RescueBot" .
The program is written in multiple files, header.h , header.cpp, main.cpp
I have a vector of objects type "Robots" and an example of my header.h file:
class Map{
private:
char World[20][20]; // The size of Map is 20 x 20
vector<Robots*>RobotsVector;
public:
Map();
vector<Robots*>*getRobotsVector();
}
// I access the vector with getRobotsVector() which belongs to Map class but returns
// Robot objects. Done this so i can access Robot objects within the Map class.
class Robots
{
private:
//some variables
public:
//some functions
virtual void movement()=0; // this is the function that handles the robots moves
virtual void action()=0; // this is the function that handles the robots actions
}
class RescueBot:public Robots{
void movement();
void action();
//some unique RescueBot stuff here
}
This is from the header.cpp file:
#include "header.h"
vector<Robots*>*Map::getRobotsVector(){return &RobotsVector;}
//example of object creation and pushing into vector
void Map::creation(){
for (int x=0;x<4;x++){
getRobotsVector()->push_back(new RescueBot);
}
}
void RescueBot::action(){
//do stuff
for(int i=0;i<Map::getRobotsVector()->size();i++){
//Here is the problem. I cant get inside the for loop
Map::getRobotsVector()->at(i)->setDamaged(false); //Changes a flag in other objects
}
}
I Have tried making the Robots class derivered class of Map. After that when i run it the vector i access in RescueBot::action is empty, while the actual vector has objects in it.
If i dont make it derivered it doesnt compile.
How can i access the vector from within the RescueBot::action() ??
The problem is that you have no Map instances.
The way you're calling it currently would only work if the getRobotsVector method were static, but you don't want that.
The reason it works when you make the Robots class a derived class of Map is because Map::getRobotsVector() would just mean you want to invoke the getRobotsVector method on the instance that the RescueBot::action function is operating on.
The solution is to pass an instance of a Map to your action functions by reference.
This is what your action function would look like then:
void RescueBot::action(Map& map) {
// Do whatever you want with the map here.
// For example:
map.getRobotsVector()->at(i)->setDamaged(false);
}

Reference to non static member function must be called

I have a vector bars that contains several coloured box objects.Each box object has it's own draw and update function. Each box moves from one side of the screen to the next side. when it's outside the screen the box should be removed. I'm using iterators to move the boxes and determine when they are outside of the screen.
I'm very new to c++ and I'm having trouble getting the code to work. the function to erase an object from a vector is giving me the error Reference to non static member function must be called. I'm reading up on static and non static members but I'm still a bit lost.
here's my main header file with the relevant code
class game : public ofxiPhoneApp {
public:
void setup();
void update();
void draw();
void exit();
vector <Colorbar> bars;
bool checkBounds (Colorbar &b);
};
in my game.mm file I create the vector and iterate over it to set the properties of the coloured bar objects:
void game::setup(){
bars.assign(5, Colorbar());
for (int i = 0; i<bars.size(); i++) {
ofColor color = colors.giveColor();
bars[i].setup();
bars[i].setColor(color.r,color.g,color.b);
bars[i].setWidth(50);
bars[i].setPos(ofGetScreenHeight()-(i*50), 0);
}
}
the update function that move the bars across the screen.
void game::update(){
for(vector<Colorbar>::iterator b = bars.begin(); b != bars.end(); b++){
(*b).update();
}
//this is the part that gives the error
bars.erase((remove_if(bars.begin(), bars.end(), checkBounds),bars.end()));
}
and here's the function to check if the box is out of bounds
bool game::checkBounds (Colorbar &b){
if (b.pos.x > ofGetScreenHeight()+50) {
// do stuff with bars vector here like adding a new object
return true;
} else {
return false;
}
}
I've done some experimenting, and making the bool checkBounds (Colorbar &b);
non-static by removing it from the header file makes the code work. but the problem is that I'd also like to be able to access the bars vector in that function to add a new object when an old one is deleted. And that won't work anymore.
How can I solve this?
You need a unary functor taking a ColourBar. A member function has an implicit first parameter for this. This means it cannot be called like this:
Colorbar cb;
game::checkBounds(cb);
It needs to be bound to an instance of its class, otherwise it would not be able to access other members of that instance. So you need to bind the checkBounds member function to an instance of game. In your case, this looks like the right instance to bind:
#include <functional> // for std::bind
using std::placeholders; // for _1
...
remove_if(bars.begin(), bars.end(), std::bind(&game::checkBounds, this, _1)) ...