modifying an object's std::vector from within another class - c++

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);
}
}

Related

How can I create the getter and setter for the vector?

Vector2D hpp files
#ifndef Vector2D_hpp
#define Vector2D_hpp
#include <iostream>
#include "Point2D.hpp"
namespace GeoBox{
class Vector2D{
Point2D m_point1{};
Point2D m_point2{};
public:
Vector2D() = default;
Vector2D(Point2D &point1, Point2D &point2)
{
m_point1 = point1;
m_point2 = point2;
}
void setVector(Point2D &point1, Point2D &point2);
};
Vector2D.cpp files
#include "Vector2D.hpp"
#include "Point2D.hpp"
void GeoBox::Vector2D::setVector(GeoBox::Point2D &point1, GeoBox::Point2D &point2) {
Vector2D(point1, point2);
}
main.cpp
int main(int argc, const char * argv[]) {
GeoBox::Point2D point1{3.0, 1.0};
GeoBox::Point2D point2{2.0, 3.0};
GeoBox::Vector2D vect1{point1, point2};
}
I am trying to create a vector consisting of 2 points. how can i create their getters and settlers? I think I created the setter function, but I'm not sure.
note:GeoBox my file name
To create a vector, you should initialize it as a template type.
For the setter function you must implement the erase () function that can receive two iterators, one that points to the value you want to delete or two iterators if you want to delete an element range pointing to the initial and last value.
 
The erase () function is already a function implemented in c ++ 11 but it can be developed.
Its seems like this might work. I changed your class to store pointers and not objects for efficiency. Granted, I can't test that this because I don't have the rest of your code and can't guarantee your setup.
#ifndef Vector2D_hpp
#define Vector2D_hpp
#include <iostream>
#include "Point2D.hpp"
namespace GeoBox {
class Vector2D {
Point2D* points[2];
public:
Vector2D() = default;
Vector2D(Point2D* point1, Point2D* point2)
{
setVector(point1, point2);
}
void setVector(Point2D* point1, Point2D* point2) {
points[0] = point1;
points[1] = point2;
}
Point2D* getVector() {
return points;
}
};
}
#endif
To do this with a struct (and without pointers in this case) you would set it up like this:
#ifndef Vector2D_hpp
#define Vector2D_hpp
#include <iostream>
#include "Point2D.hpp"
namespace GeoBox {
class Vector2D {
struct Vector { //Define the struct
Point2D point1;
Point2D point2;
} points; //Create instance of struct
public:
Vector2D() = default;
Vector2D(Point2D point1, Point2D point2)
{
setVector(point1, point2);
}
void setVector(Point2D i_point1, Point2D i_point2) {
points.point1 = i_point1; //Access struct components
points.point2 = i_point2;
}
Vector getVector() {
return points; //return struct
}
};
}
#endif
Pointers can (and should) still be used in this case however as they allow for increased speed in your program overall.

Destroyer gets called right after constructor [closed]

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.

FLTK C++ Fl_line don't draw

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.

C++ Polymorphism issues. Something to do with _vfptr

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 = &rect;
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 = &rect;
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 = &rect;
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.

Rectangle draw and print method

I have an assignment where I am supposed to draw a rectangle shape, the way is to specify two points in a plane, draw two horizontal and two vertical lines. We are supposed to use the Point class in the Rectangle class.
I have the assignment instructions .h (point class), .cpp (Point class), .h (Rectangle class), .cpp (Rectange class) and the main. I didn't do too much in main but specified what should be done. He wants a rectangle drawn with the outline consisting of the y's or the character y.
I think everything is good in the .h (point class), .cpp (Point class), .h (Rectangle class), but I am having issues with the draw method and print method of the Rectangle .cpp, the instructor said to just use a temp variable for the origin in the draw method or something like that,
Also not sure about the print method in the .cpp Rectangle file, would appreciate help here. Tried to compile but all hell broke loose, any explanation/example would help a lot.
Point.h
//Point.h
#include <iostream.h>
/* The Point class Header file (Point.h) */
#ifndef POINT_H
#define POINT_H
class Point {
private:
double x,y;//x and y are private variables
public:
Point(int x, int y):x(x),y(y){}//use initialization list
double getX() const; //Getters
double getY() const;
void setX(double x); //Setters
void setY(double y); //Setters
void print()const;
//Overload '+' operator
const Point operator +(const Point & rt)const;
//Overload '-' operator
const Point operator - (const Point &rt)const;
Point operator +=(Point & rt);
Point operator -=(Point & rt);
//Overload '==' operator comparing two points
int operator ==(Point &rt);
int operator <(Point &rt);
int operator >(Point &rt);
int operator <=(Point &rt);
int operator >=(Point &rt);
};
/* POINT_H */
#endif
Point .cpp
//the Point.cpp file
#include "Point.h"
#include<iostream>
using namespace std;
//Getters
double Point::getX()const {return x;}
double Point::getY()const {return y;}
//setters
void Point::setX(double x) {this->x=x;}
void Point::setY(double y) {this->y=y;}
//Public functions
void Point::print()const{
cout << "(" << x << "," << y << ")" << endl;
}
//overloading '+' operator
const Point Point::operator+(const Point & rt) const{
return Point(x + rt.x, y + rt.y);
}
const Point Point::operator-(const Point & rt) const{
return Point(x - rt.x, y - rt.y);
}
Point Point::operator+=(Point & rt){
return Point(x+=rt.x, y+=rt.y);
}
int Point::operator ==(Point & rt){
return (x == rt.x && y==rt.y);
}
int Point::operator <(Point & rt){
return (x < rt.x && y<rt.y);
}
int Point::operator >(Point & rt){
return (x > rt.x && y>rt.y);
}
int Point::operator <=(Point & rt){
return (x <= rt.x && y<=rt.y);
}
int Point::operator >=(Point & rt){
return (x >= rt.x && y>=rt.y);
}
//;
//;
//END POINT.CPP
Rectangle h file
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <iostream.h>
#include "Point.h"
class Rectangle {
private:
Point origin;
Point corner;
public:
Rectangle (const Point & or, const Point & cr):origin(or),corner(cr) {}
// void move(int dx, int dy);
void draw();
void print()const;
};
#endif /* RECTANGLE_H */
Rectangle .cpp file
/* The Rectangle.cpp file) */
#include "Point.h"
#include "Rectangle.h"
#include <iostream.h>
#include <string>
#include <conio.h>
using namespace std;
// Public Functions
void Rectangle::print() const
{
cout<<"(" <<origin <<"," <<corner << ")" <<endl;
}
void Rectangle::draw()
{
Point temp=origin; //store origin in temp object
while (temp.getX() < corner.getX()) {
putch('y');
}
/* int temp=origin;
for (int x = temp.getX(); x < center.getX(); x++) {
Point pt1 (x, temp.getY());
Point pt2 (x, center.getY());
pt1(6,4);
// move to p1 // not sure how to do this
putCH ('y');
pt2(30,15);
// move to p2 //not sure how to do this
putCH ('y');
}
for (int y = lowerRight.getY(); y < upperLeft.getY(); y++) {
Point pt1 (origin.getX(),y);
Point pt2 (corner.getX(),y);
pt1(6,4);
//move to p1 //not sure how to do this
putCH('y');
pt2(30,15);
// move to p2 //not sure how to do this
putCH ('y');
}*/
//return 0;
}//;
MAIN
#include "Point.h"
#include "Rectangle.h"
#include <iostream>
#include <conio.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
//char y;
Point p1(6, 4), p2(30, 15);
//cout<<"\n the origin of Rectangle is at: ";
//p1.print();
//cout<<"\n the opposite corner of rect is at:";
//p2.print();
Rectangle r1(p1,p2);
r1.draw();
clrscr();
gotoxy(1,20);
//r1.print();
getch();
return 0;
} //;
//END OF MAIN
I could see one C++ specific issue: you did not overload "<<" operator on Point. First please do that.
Secondly, which compiler are you using?
clrscr(); gotoxy();
are not part of standard C+++.
If your compiler supports them, well and good.
Otherwise, you need to look for alternatives.
Good convention: avoid
using namespace std;
Instead, write
std::cout
std::endl;
etc
I did not go through your actual logic.
Which is actually your assignment - isnt't it?