operator overloading and linked data structures
- Practice class design with the Point and Cluster classes, which feature dynamic memory management.
- Learn to overload operators for your own classes/types.
- Learn to work with linked lists, one of the most basic and ubiquitous data structures.
- Practice input/output within the streams abstraction.
- Continue using git and Github.
- Develop good coding style.
PA2 asks you to update your 3D Point class from PA1 to an arbitrary number of "dimensions", and to create a Cluster class which will hold a big number of Point objects. The Point objects held in a Cluster have to be sorted in pseudo-lexicographic order at all times. You have to write two files, Point.cpp and Cluster.cpp. See the Detailed Instructions at the bottom of this file.
PA2 is in the test-driven-development (TDD) style, just like PA1. It has 204 tests that your implementation should pass for full points. Start by creating the two files Point.cpp and Cluster.cpp so CMake will stop complaining. (Remember to git add them to your local repository.) Then start implementing the Point class incrementally. You can comment out all but the first test (test_point_smoketest(ec);) in main.cpp. When you pass this test, uncomment the next one, and so on.
PA2 is a much larger assignment than PA1. You should expect to write about 500 lines of code and spend about 30 hours on it. Therefore, it is advisable that you start early and do it in stages. If you get stuck on anything for more than one hour, seek help.
You don't need to submit anything. Once you fork the repository (this is your remote repository on Github, aka origin), you will clone it to your development machine (this is your local repository), and start work on it. Commit your changes to your local repository often and push them up to the remote repository occasionally. Make sure you push at least once before the due date. At the due date, your remote repository will be cloned and tested automatically by the grading script. Note: Your code should be in the master branch of your remote repository.
An autograding script will run the test suite against your files. Your grade will be based on the number of tests passed. (E.g. if your code passes 3 out of 6 test cases, your score will be 50% and the grade will be the corresponding letter grade in the course's grading scale). The test suite for PA2 has 204 tests. Note: The testing and grading will be done with fresh original copies of all the provided files. In the course of development, you can modify them, if you need to, but your changes will not be used. Only your Point.cpp and Cluster.cpp files will be used.
Your program should run on GCC 4.9.0 or later, or Clang 3.3 or later. No other compilers are supported.
The assignment is due on Wed, Mar 2, at 23:59 Mountain time. The last commit to your PA2 repository before the deadline will be graded.
Free Github repositories are public so you can look at each other's code. Please, don't do that. You can discuss any programming topics and the assignments in general but sharing of solutions diminishes the individual learning experience of many people. Assignments might be randomly checked for plagiarism and a plagiarism claim may be raised against you.
For this assignment, no exteranal libraries should be used, except for the Standard Library minus the Standard Template Library (STD). The implementation of the linked list should be your own. We will use the STD in PA3-PA5.
Familiarize yourself with and start following these coding style guidelines. There are others on the Web. Pick one and be consistent. Note: If you stumble on the Google C++ Style Guide, be advised that it has been heavily criticized by many leading C++ programmers. I don't advise you to follow it, especially the more advanced features. This Guide is for entry-level coders at Google who need to be able to work with their legacy code. It is not advisable for new projects and novice programmers.
Operator overloading guidelines.
A very good C++ tutorial, including many topics we are covering.
Two websites with C++ Reference, here and here.
-
The
Point
class represents a point in multidimensional Euclidean space, represented bydouble
values. The number of dimensions is an argument to thePoint
constructor. The values of the point should be held in a private dynamically allocated array ofdouble
s. To handle dynamic memory properly, you have to implement the one-argument constructor, the copy constructor, the assignment operator, and the destructor (the last three are aka the big three). -
The optional second constructor, which takes a number of dimensions and an array of
double
s, is not tested by the test suite. It might be useful for your own testing & debugging needs. -
Every
Point
should have a unique id. The easiest way to achieve this is to use astatic
variable that holds the value of the next id. (Astatic
variable belongs to the class, not the objects, so there is only one such variable, no matter how many objects of the class are created.) ThePoint
constructor should get the current value to assign to the current point, and increment the value for the next point.Note: The
static
variable has to be defined and initialized in the Point.cpp file as follows:unsigned int Point::__idGen = 0; // id generator
-
For the proper operation of the
Point
andCluster
classes, thePoint
copy constructor and assignment operator implementations should copy the id of the argument, and not generate a new one like the constructor(s). -
Modify the
distanceTo()
function to work for points of arbitrary number of dimensions. Remember that the dimensionality of thePoint
is held in a private variable. -
Implement the overloaded member
operator*=
andoperator/=
with a singledouble
argument. These operators are known as compound assignment.Usage: Each dimension of the current
Point
is multiplied or divided by a factor as follows:p1 *= 6.3; p2 /= 2.5;
-
Implement the overloaded simple arithmetic member
operator*
andoperator/
with a singledouble
argument.Usage: A new
Point
is created and returned with dimensions like the currentPoint
but multiplied or divided by a factor as follows:p1 = p * 6.3; p2 = p * 2.5;
Note: The implementation of these operators is straightforward if the corresponding compound assignment operators are used.
-
Implement the overloaded non-
const
subscript memberoperator[]
.Usage: Read/write access to each of a
Point
's values:p[4] = 7.001; p[5] = p[1] * 1.5;
-
Implement the overloaded
friend
compound assignment arithmeticoperator+=
andoperator-=
with twoconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.Usage: Dimension-wise addition/substraction of the right-hand
Point
from the left-handPoint
:p1 += p2; p3 -= p1;
Note: Notice that the first (or left-hand) argument is not
const
. The operators modify thatPoint
and return a reference to it. -
Implement the overloaded
friend
simple arithmeticoperator+
andoperator-
with twoconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Dimension-wise addition/substraction of the right-hand Point
from the left-hand Point
and the creation and returning of a new const Point
with the dimension-wise sum/difference of their values:
p1 = p2 + p3;
p3 = p1 - p4;
Note: The implementation of these operators is straightforward if the corresponding compound assignment operators are used.
Note: The return type is a const
to prevent silly statements like the following:
(p1 + p3) = p5; // assigns p5 to the temporary new Point object returned by operator+
- Implement the overloaded
friend
operator==
andoperator!=
with twoconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Test two Point
s for equality or inequality:
if (p1 == p2) {
// ...
}
if (p3 != p4) {
// ...
}
Note: Two Point
s are equal iff all values are equal dimension-wise, and the id-s are also equal.
Note: The implementation of operator!=
is straightforward with the use of operator==
.
- Implement the overloaded
friend
operator<
,operator>
,operator<=
, andoperator>=
with twoconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Compare two Point
s:
if (p1 < p2) {
// ...
}
if (p3 >= p4) {
// ...
}
Note: One Point
is smaller than another iff, for a given dimension position, the value of the first point is less than the value of the second point, and all the values on the left, if any, are all equal. The values on the right don't matter. For example, Point
(5.0, 5.0, 4.5, 10.1, 13.4, 151.3) is smaller than (5.0, 5.0, 4.5, 10.1, 13.5, 15.9).
Note: Implement operator<
, then use it to implement operator>
and operator>=
. Finally, use operator>
to implement operator<=
.
- Implement the overloaded
friend
insertionoperator<<
with astd::ostream
and aconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Right out (intert) a Point
to an output stream:
cout << p2 << endl;
Note: A Point
should write itself out as follows (note the space after each comma):
1.2, 4.5, 6.7, 90.12, 34.54, 0.01
- Implement the overloaded
friend
extractionoperator>>
with astd::istream
and a non-const
Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Read in (extract) a Point
from an input stream:
std::string pointString("1.2, 4.5, 6.7, 90.12, 34.54, 0.01");
std::stringstream inputStringStream(pointString);
Point p(6);
inputStringStream >> p;
Note: Notice that the Point
created to be read has exactly the dimensionality that is necessary to hold the values read out from the input stream.
-
The
Cluster
class represents a collection ofPoint
objects. It uses a singly-linked list to hold them in ascending pseudo-lexicographic order. The list is composed of linkedLNode
objects defined as simple structures, each one pointing to the next one, if any, and the last one holding anullptr
, signifying the end of the list:typedef struct LNode *LNodePtr; struct LNode { Point point; LNodePtr next; LNode(const Point &p, LNodePtr n); };
-
A
Cluster
can havePoint
s added and removed. During these operations, two conditions have to be maintained: -
The
Point
s should always be in the correct ascending pseudo-lexicographic order. -
The
size
parameter of theCluster
should always be in sync with the true number ofPoints
. -
It is helpful to employ the following two techniques in the implementation of the linked-list manipulation methods:
-
Handle separately and in this order the cases of * Empty list * The first element of the list * All the rest of the elements
-
When traversing the list keep track of two variables * A pointer to the current element (e.g.
curr
) * A poitner to the previous element (e.g.prev
) -
A linked list is dynamically allocated data structure, so you need to implement the big three (cpy ctor, oper=, and dtor) to manage it correctly. In PA2,
Cluster
has a default constructor, which initializes an empty list. -
The optional private helper methods
void __del(); void __cpy(LNodePtr pts); bool __in(const Point &p) const;
can be used to reuse code.
__del
is used in the destructor and overloaded assignment operatoroperator=
,__cpy
is used in the copy constructor andoperator=
, while__in
can be helpful for testing, debugging, and even some method implementations. -
Implement the members
add
andremove
to addPoint
s to and removePoint
s from aCluster
. Notice theconst Point &
arguments and return value forremove
. The latter allows for aPoint
to be moved from oneCluster
to another in one line of code, as follows:c5.add(c3.remove(p23));
Note:
add
should create a newPoint
using the copy constructor and not add the argument directly, since it cannot have knowledge about the allocation of the referenced object. If that object is destroyed as its scope is exited, the added object will become invalid after the addition. -
Implement the member
contains
to returntrue
orfalse
if theCluster
contains aPoint
equal (byPoint::operator==
) to the object referenced in the argument. -
Implement the
const
member subscriptoperator[]
to return aconst
reference to a particularPoint
in the ordered linked-list. ThePoint
cannot be modified. Note: Don't overuse this operator, because it is very inefficient for a singly-linked list. -
Implement the compound assignment member
operator+=
andoperator-=
with aconst Point &
argument.Usage: Add a
Point
to or remove one from theCluster
:c5 += p56; c2 -= p98;
Note: Implementation is straightforward through the use of
add
andremove
. -
Implement the simple arithmetic
friend
operator+
andoperator-
with oneconst Cluster &
and oneconst Point &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Create and return a new Cluster
with the argument Point
added to or removed one from the argument Cluster
:
c7 = c5 + p56;
c9 = c2 - p98;
Note: Implementation is straightforward through the use of operator+=
and remove-=
.
- Implement the compound assignment member
operator+=
andoperator-=
with aconst Cluster &
argument. The addition of twoCluster
s results in a union of the two, which contains all the unique points contained in eitherCluster
. For example, ifc5
containsp12, p45, p78
andc6
containsp23, p45, p90
, then then the union ofc5
andc6
would containp12, p23, p45, p78, p90
. The subtraction of twoCluster
s results in an asymmetric difference of the two. For example, ifc5
containsp12, p45, p78
andc6
containsp23, p45, p90
, then then the left assymetric difference ofc5
andc6
(that is,c5 - c6
) would containp12, p78
, while the right assymetric difference ofc5
andc6
(that is,c6 - c5
) would containp23, p90
.
Usage: Make the calling Cluster
object the union or assymetric difference of itself and the argument Cluster
object:
c5 += c6;
c2 -= c8;
- Implement the simple arithmetic
friend
operator+
andoperator-
with twoconst Cluster &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Create and return a new Cluster
object that is the union or assymetric difference of the the two argument Cluster
objects:
c10 = c5 + c6;
c11 = c2 - c8;
Note: Implementation is straighforward through the use of operator+=
and operator-=
.
- Implement the equality and inequality comparison
friend
operator==
andoperator!=
with twoconst Cluster &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Check if two Cluster
s are equal or unequal:
if (c3 == c5) {
// ...
}
if (c3 != c4) {
// ...
}
Note: Two Cluster
s are equal iff they contain the same Point
s (by Point::operator==
).
- Implement the overloaded
friend
insertionoperator<<
with astd::ostream
and aconst Cluster &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Right out (intert) a Cluster
to an output stream:
cout << c7 << endl;
Note: A Cluster
should write itself by writing its Point
s in order, each on a separate line, as follows (note the space after each comma):
1.2, 4.5, 6.7, 90.12, 34.54, 0.01
2.2, 4.5, 6.7, 90.12, 34.54, 0.01
3.2, 4.5, 6.8, 91.02, 34.04, 0.11
- Implement the overloaded
friend
extractionoperator>>
with astd::istream
and a non-const
Cluster &
arguments. Afriend
operator is a non-member function with private access to the class where it is declared.
Usage: Read in (extract) a Cluster
from an input stream:
std::ifstream csv("points.csv");
Cluster c;
if (csv.is_open()) {
csv >> c;
csv.close();
}
where the file points.csv contains
00002.3,5.6,0,5.6,7.9
1.3, 4.3, 0, 5.6, 7.9
2.4 , 5.6 , 0, 6.6 , 7.1
4.1,5.6,5,1.6,7.9
Note: The Cluster
reads the input stream line-by-line, creates a Point
with the right dimensionality for each line, and then delegates the reading of the line to the operator<<
for Point
.
-
The
Point
andCluster
classes are created inside anamespace
, as follows:namespace Clustering { class Point { }; }
-
Both the class declarations and the method implementations have to wrapped with the
namespace Clustering {}
blocks. -
When using the
Point
andCluster
classes, the namespace has to be specified, as follows:#include "Point.h" #include "Cluster.h" using Clustering::Point; using Clustering::Cluster; int main() { Point p1(10); Cluster c1; // ... return 0; }
or
#include "Point.h" #include "Cluster.h" using namespace Clustering; int main() { Point p1(10); Cluster c1; // ... return 0; }
or
#include "Point.h" #include "Cluster.h" int main() { Clustering::Point p1(10); Clustering::PCluster c1; // ... return 0; }