Best way to store objects in a class

For one of my projects, we had to make a class called Rectangle2D. It contains 4 data fields. X and Y which indicate the center of the rectangle and then the width and height. We use some functions to determine if rectangles are overlapping and such, but my question is on storing these rectangles. I have it all done except this last part, "Modify your Rectangle2D class to store multiple rectangles while supporting all the member functions, including the constructors." I'm not really sure how to go about this. I looked around online and found some things about using vectors and linked lists, but I don't know too much about either. Any suggestions? Thanks in advance.
Wow, that's a nice one ;-)

Well, I would suggest you start with a fresh new class, e.g. "Rectangle2DCollection" and give this one member: "std::vector<Rectangle2D> rects;" or so. Then start implementing in the new class all functions that were part of the original Rectangle2D class (like "isOverlapping()"). However, whereever you would have passed a Rectangle2D, you now use Rectangle2DCollection and you have to change the logic inside the functions, of course.

For the constructors.. if you have parameter that can only be used to construct one single Rectangle2D (e.g. "int x, int y, int width, int height") then you just create one single Rectangle2D in your vector.

Using std::vector<Rectangle2D> is pretty simple, actually.

1
2
3
4
5
6
7
8
9
10
11
12
std::vector<Rectangle2D> rects;
Rectangle2D someRect(50,50,100,100);

// add a new value to the list of rectangles
rects.push_back(someRect);

// doing stuff with each rectangle in the list:
for (int i = 0; i < rects.length(); ++i)
{
    Rectangle2D& r = rects[i];
    // do something with r
}


If you need to remove rectangles from the list, come back here. Thats a bit more complex. (But only a bit ;-)

Ciao, Imi.
Last edited on
This is what I ended up doing but I have one issue...my destructor. Any ideas on how I can set it to delete a specific object in the array. As of right now I have it set to delete the only object that gets deleted in the program, but I'm sure that my instructor will catch that and I'm lost on how to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef RECTANGLE2D_H
#define RECTANGLE2D_H
#include <vector>
using namespace std;

static int numberOfRectangles = 0;

class Rectangle2D
{
public:
	Rectangle2D();
	Rectangle2D(double, double, double, double);
	~Rectangle2D();
	Rectangle2D(Rectangle2D &);
	double getX() const;
	double getY() const;
	double getWidth() const;
	double getHeight() const;
	void setX(double);
	void setY(double);
	void setWidth(double);
	void setHeight(double);
	double getArea();
	double getPerimeter();
	bool contains(double, double);
	bool contains(Rectangle2D &);
	bool overlaps(Rectangle2D &);
	static int getNumberOfRectangles();
	static vector<Rectangle2D*> getCollection();

private:
	double x, y, width, height;
};
static vector<Rectangle2D*> Collection;

#endif 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "Rectangle2D.h"
#include <iostream>
using namespace std;



Rectangle2D::Rectangle2D()
{
	x = 0;
	y = 0;
	width = 1;
	height = 1;
	numberOfRectangles++;
	Collection.push_back(this);
	cout << "Object added. Number of Rectangles: " << Rectangle2D::getNumberOfRectangles() << endl;
	cout << "Number of objects in Collection: " << Collection.size() << endl;
}
Rectangle2D::Rectangle2D(double newX, double newY, double newWidth, double newHeight)
{
	x = newX;
	y = newY;
	width = newWidth;
	height = newHeight;
	numberOfRectangles++;
	Collection.push_back(this);
	cout << "Object added. Number of Rectangles: " << Rectangle2D::getNumberOfRectangles() << endl;
	cout << "Number of objects in Collection: " << Collection.size() << endl;
}
double Rectangle2D::getX() const
{
	return x;
}
double Rectangle2D::getY() const
{
	return y;
}
double Rectangle2D::getWidth() const
{
	return width;
}
double Rectangle2D::getHeight() const
{
	return height;
}
void Rectangle2D::setX(double newX)
{
	x = newX;
}
void Rectangle2D::setY(double newY)
{
	y = newY;
}
void Rectangle2D::setWidth(double newWidth)
{
	width = newWidth;
}
void Rectangle2D::setHeight(double newHeight)
{
	height = newHeight;
}
double Rectangle2D::getArea()
{
	return width * height;
}
double Rectangle2D::getPerimeter()
{
	return 2 * (width + height);
}
bool Rectangle2D::contains(double x, double y)
{
	if(x <= this->x + width / 2 && x >= this->x - width / 2)
		if(y <= this->y + height / 2 && y >= this->y - height / 2)
			return true;
	return false;
}
bool Rectangle2D::contains(Rectangle2D &r)
{
	if((this->x + width / 2) >= (r.getX() + r.getWidth() / 2) && (this->x - width / 2) <= (r.getX() - r.getWidth() / 2))
		if((this->y + height / 2) >= (r.getY() + r.getHeight() / 2) && (this->y - height / 2) <= (r.getY() - r.getHeight() / 2))
			return true;
	return false;
}
bool Rectangle2D::overlaps(Rectangle2D &r)
{
	if((this->x + width / 2) <= (r.getX() + r.getWidth() / 2) && (this->x - width / 2) >= (r.getX() - r.getWidth() / 2))
		if((this->y + height / 2) <= (r.getY() + r.getHeight() / 2) && (this->y - height / 2) >= (r.getY() - r.getHeight() / 2))
			return true;
	if((this->x + width / 2) >= (r.getX() + r.getWidth() / 2) && (this->x - width / 2) <= (r.getX() + r.getWidth() / 2))
		return true;
	if((this->x + width / 2) >= (r.getX() - r.getWidth() / 2) && (this->x - width / 2) <= (r.getX() - r.getWidth() / 2))
		return true;
	if((this->y + height / 2) >= (r.getY() + r.getHeight() / 2) && (this->y - height / 2) <= (r.getY() - r.getHeight() / 2))
		return true;
	if((this->y + height / 2) >= (r.getY() - r.getHeight() / 2) && (this->y - height / 2) <= (r.getY() - r.getHeight() / 2))
		return true;
	return false;
}
int Rectangle2D::getNumberOfRectangles()
{
	return numberOfRectangles;
}
vector<Rectangle2D*> Rectangle2D::getCollection()
{
	return Collection;
}
Rectangle2D::~Rectangle2D()
{
	numberOfRectangles--;
	Collection.erase(Collection.begin()+3);
	cout << "Object has been deleted. Number of Rectangles remaining: " << Rectangle2D::getNumberOfRectangles() << endl;
	cout << "Number of objects remaining in Collection: " << Collection.size() << endl;


}
Rectangle2D::Rectangle2D(Rectangle2D &r)
{
	x = r.getX();
	y = r.getY();
	width = r.getWidth();
	height = r.getHeight();
	numberOfRectangles ++;
	Collection.push_back(this);
	cout << "Object copied. Number of Rectangles: " << Rectangle2D::getNumberOfRectangles() << endl;
	cout << "Number of objects in Collection: " << Collection.size() << endl;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <vector>
#include "Rectangle2D.h"
using namespace std;

int main()
{
	//Test getNumberOfRectangles fuction
	cout << "Number of rectangles to begin with: " << Rectangle2D::getNumberOfRectangles() << endl << endl;
	//Rectangle 1
	Rectangle2D *r1 = new Rectangle2D(2, 2, 5.5, 4.9);
	cout << "r1 parameters are: x = " << (*r1).getX() << ", y = " << (*r1).getY() << ", Width = " << (*r1).getWidth()
		<< ", Height = " << (*r1).getHeight() << endl;
	cout << "The perimeter of r1 is: " << (*r1).getPerimeter() << ". The area of r1 is: " << (*r1).getArea() << "." << endl << endl;
	//Rectangle 2
	Rectangle2D *r2 = new Rectangle2D(4, 5, 10.5, 3.2);
	cout << "r2 parameters are: x = " << (*r2).getX() << ", y = " << (*r2).getY() << ", Width = " << (*r2).getWidth()
		<< ", Height = " << (*r2).getHeight() << endl;
	cout << "The perimeter of r2 is: " << (*r2).getPerimeter() << ". The area of r2 is: " << (*r2).getArea() << "." << endl << endl;
	//Rectangle 3
	Rectangle2D *r3 = new Rectangle2D(3, 5, 2.3, 5.4);
	cout << "r3 parameters are: x = " << (*r3).getX() << ", y = " << (*r3).getY() << ", Width = " << (*r3).getWidth()
		<< ", Height = " << (*r3).getHeight() << endl;
	cout << "The perimeter of r3 is: " << (*r3).getPerimeter() << ". The area of r3 is: " << (*r3).getArea() << "." << endl << endl;
	//Test contains and overlap functions
	cout << "Does r1 contain (3, 3)? (0 = no, 1 = yes): " << (*r1).contains(3, 3) << endl << endl;
	cout << "Does r1 contain r2? (0 = no, 1 = yes): " << (*r1).contains(*r2) << endl << endl;
	cout << "Does r3 overlap r1? (0 = no, 1 = yes): " << (*r1).overlaps(*r3) << endl << endl;
	//Rectangle 4
	Rectangle2D *r4 = new Rectangle2D(*r1);//copy constructor
	cout << "r4 added as a copy of r1." << endl;
	cout << "r4 parameters are: x = " << (*r4).getX() << ", y = " << (*r4).getY() << ", Width = " << (*r4).getWidth()
		<< ", Height = " << (*r4).getHeight() << endl;
	cout << "The perimeter of r4 is: " << (*r4).getPerimeter() << ". The area of r4 is: " << (*r4).getArea() << "." << endl << endl;
	//Test setters
	(*r4).setX(4);
	(*r4).setY(4);
	(*r4).setWidth(10);
	(*r4).setHeight(10);
	cout << "r4 has been modified. New parameters are: x = " << (*r4).getX() << ", y = " << (*r4).getY() << ", Width = " << (*r4).getWidth()
		<< ", Height = " << (*r4).getHeight() << endl;
	cout << "The perimeter of r4 is: " << (*r4).getPerimeter() << ". The area of r4 is: " << (*r4).getArea() << "." << endl << endl;
	//Test destructor
	delete r4;
	//Test getCollection function
	cout << "Rectangles in Collection at end: " << Rectangle2D::getCollection().size() << endl;
	return 0;
}

Last edited on
I have another question as well. How can I call my data fields through the vectors? I tried this but it didn't work.
cout << (*Collection[1]).getHeight();
Collection[1]->getHeight()

Your design needs a lot of improvement, by the way. As a rule of thumb, if you're passing this to a function (in this case, line 122), you're doing something wrong.
Rectangle2D's destructor is highly likely to mess the program's state if it's ever called.
Last edited on
Yeah, I know it needs some work. This is some more advanced stuff for me. I tried the Collection[1]->getHeight() and it compiles but makes the program fail mid run. It says vector subscript out of range. The destructor works just fine, other than I am unsure how to delete a specific object.

So I don't know why exactly, but I seem to have 2 Collection vectors. When I put this in main
1
2
3
Rectangle2D *r1 = new Rectangle2D(2, 2, 5.5, 4.9);
Collection.push_back(r1);
cout << Collection.size() << Collection[0]->getX() << endl;

it works just fine and will output 1 and 2 like it should, while my Collection.size() in my implementation code will output 0 (if I remove the collection.push_back(this) from the constructors). This also works vice versa which is why I made the getCollection function when I shouldn't need it.

I'm pretty stumped on this.
Last edited on
AFAICT from the code you posted, there's only one Collection.

It's also interesting, but unrelated, to note that Rectangle2D::getCollection() is a) completely useless, and b) returning a copy of Collection.
It should be completely useless, but in the original program I posted, when I use cout << Collection.size(); in main it outputs 0, but when I use it in the constructor it outputs the right number of objects. The only way I have found to get both of them to be accurate, is if I use Collection.push_back(this) in the constructor and then also add it in the main with Collection.push_back(r1). Otherwise it acts like they are separate vectors. Is this how it is supposed to work or what?
Oh, there it is. Yeah, now I see it. There's one symbol named 'Collection' per source file because you declared it as static, which makes the object local to the translation unit in which it is declared. Since both sources include the header, there are two 'Collection's.
Shouldn't this "#ifndef RECTANGLE2D_H #define RECTANGLE2D_H" have taken care of that?
Macros are local, so to speak, to translation units. If that wasn't the case, you couldn't include the header in more than one file. Instead, the inclusion guard prevents you from including the header twice in the same file.
I see. So how would you recommend I fix this?
Either change static to extern and copy the line to either source sans the extern; or move the declaration into the class, making it a static member, and define it in Rectangle2D's source.
What do you mean by this,
copy the line to either source sans the extern
?
Topic archived. No new replies allowed.