-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path03.source.cpp
More file actions
205 lines (173 loc) · 5.44 KB
/
03.source.cpp
File metadata and controls
205 lines (173 loc) · 5.44 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <iostream>
using namespace std;
struct Point
{
int x;
int y;
// Structs can have functions *inside* them! We call them "methods".
void print()
{
// @Reminder: the type of `this` is `Point* const`. In other words, an
// immutable (const) pointer to a mutable (non-const) Point instance.
// @Reminder: all variables (member fields) of the object on which this
// method is called (point.print()) are available like local variables
// here.
// Another way to write `x` is `this->x` or `(*this).x`.
cout << "(" << x << ";" << y << ")";
}
};
struct Circle
{
// struct inside struct - no problem!
// Benefits: we can reuse Point's functionality. E.g. we can call
// `p.print()` instead of writing manually `cout << x << ' ' << y;`.
Point p;
double r;
void print()
{
cout << r << " ";
p.print();
cout << endl;
}
};
struct Rectangle
{
Point p;
double width;
double height;
void print()
{
cout << width << " " << height << " ";
p.print();
cout << endl;
}
};
struct Window
{
// @TODO use DynamicArray instead of bare pointers
Circle* circles;
Rectangle* rectangles;
void print()
{
// @TODO Figure out what to do with 'n' here.
// for(int i = 0; i < n; ++i) {
// circles[i].print();
// }
// for(int i = 0; i < n; ++i) {
// rectangles[i].print();
// }
}
};
int count_alloc = 0;
// NOTE: A TEMPLATE!
// Lets us generate structs based on a given type (one or more) which we choose
// on object construction (we call this "template instantiation").
template <typename T> struct DynamicArray
{
// Usage of T!
// Gets replaced with the actual type we pass. E.g. DynamicArray<Circle>
T* array;
/*
* Constructor - an automatically called function on object initialization.
* @TODO: check what happens if you pass n = 0, i.e. what does `new T[0]`
* do. Look it up on the internet and explain what you observed.
*
* @TODO. Proper initialization of the member fields
*/
DynamicArray(unsigned n)
{
array = new T[n];
cout << "Dynamic array allocated #" << (count_alloc++) << endl;
}
/*
* Pushes an element at the end of the array, or rather creates a new array
* from the old with one element more at the right end.
* @TODO think: how to get rid of the `size` parameter?
*/
void push(int size, const T& newElement)
{
// 1. Allocate memory for the updated array of size one more than
// this->array.
// @TODO think: how to optimize memory allocations when push() is called
// multiple times on the same instance.
T* extended = new T[size + 1];
// 2. Move everything from this->array to `extended`.
// Elements range from the 0th to (size - 1)th index.
for (int i = 0; i < size; ++i)
extended[i] = array[i];
// 3. Note that we didn't put anything in the last position of
// `extended` - `extended[size]` (remember, it's size is (size + 1)).
// We copy the element passed as an argument into the new array.
extended[size] = newElement;
// 4. NOTE: The old memory is currently referenced by the current value
// of this->array. We free the memory for the old array as it's not
// needed anymore.
delete[] array;
// 5. Unless we execute the following line, this->array will point to
// the old memory block which we just released back to the operating
// system. We finish by reassigning `this->array` to point to the newly
// allocated `extended`.
array = extended;
// @TODO think: what would happen if we swap the last two actions?
}
/*
* Removes the n'th element, or rather creates a new array from the old with
* its n'th element removed.
* @TODO think: how to get rid of the `size` parameter?
*/
void deleteAt(unsigned size, unsigned n)
{
// Allocate memory for the shrunken array
T* shrunken = new T[size - 1];
// Copy everything from `array` into `shrunken`, except for the array[n]
// NOTE: Can be done with 2 `for` loops without conditional blocks.
for (int i = 0; i < size; ++i) {
if (i < n) shrunken[i] = array[i];
if (i > n) shrunken[i - 1] = array[i];
}
// NOTE: The old memory is currently referenced by the current value of
// this->array. We free the memory for the old array as it's not needed
// anymore.
delete[] array;
// Unless we execute the following line, this->array will point to the
// old memory block which we just released back to the operating system.
// We finish by reassigning `this->array` to point to the newly
// allocated `extended`.
array = shrunken;
}
/*
* Destructor - a special function, automatically called when the object
* leaves scope (the set of curly braces it was defiend within).
*
* An easy way not to forget to free whatever you allocated!
*/
~DynamicArray()
{
delete[] array;
cout << "~DynamicArray(): memory cleared." << endl;
}
};
int main()
{
Point p{5, 10};
Rectangle r{p, 3, 4};
Circle c{p, 6};
// Method calls! Note the special syntax.
p.print(); // The `this` inside the print() function equals `&p`.
c.print();
unsigned n = 2; // Too lazy to input ever time.
// NOTE: Template instantiation. Generates a struct where every `T` is
// replaced with `Circle`, and compiles it separately.
// NOTE: We call the constructor with 'n' as an argument
DynamicArray<Circle> circles{n};
// Method call with 2 arguments!.
circles.push(n, c);
DynamicArray<Rectangle> rectangles{n};
// @TODO fix Window and make the following code work:
// Window w1{circles, rectangles};
// Window w2{circles, rectangles};
// w1.print();
// cout << endl;
// w2.print();
return 0;
}