|
|
c m s c 214
f a l l 2 0 0 1 |
No. You should be able to compare objects stored in the array list with operator< and operator==, just as is done for STL vectors.
No. That way, you can distinguish them.
Shrug. You can try to finish the second project, and submit a "buggy" version, then clean up the code so that it passes the secondaries. This would give you the most time to submit something without the late penalties. You might lose points on the secondaries, so you have to weigh that.
Good testing on project 1 might have helped (or at least, testing project 1 if you know there might be errors, even at the start of Project 2).
These act like pointer addition/subtraction. Recall that an iterator is a pointer (or contains one called curr). You should return a temporary copy of the pointer plus or minus the offset. Don't worry if this goes out of bound. After all, there's no such checks in C/C++.
Recall what pointer arithmetic does. Suppose you have a pointer. It points to an int. You can PRETEND that this int is an int inside an array (even though pointer arithmetic will work irrespective of whether the pointer points to an array element or not). When you add one to the pointer, it returns a TEMPORARY pointer that points to the next element in the array. If you add 2 to the original pointer, then it returns a TEMPORARY pointer to 2 elements past the element it is pointing too.
operator+ and operator- should NOT change where "curr" points to. Instead, either make a temporary iterator, setting the temporary iterator to "curr" plus or minus the offset. Then, return that iterator.
This is true. Please look at the updated Project 2 description, posted since Thursday afternoon. In a nutshell,
Yes, you can do this.
No. The number of elements should remain the same (this also happens in STL vectors). Fortunately, if you assume there are no duplicates, then when you sort, it OUGHT to handle duplicates just fine.
No. I've decided to remove that as a requirement.
No. It's just a core dump without a core dump. It is a memory problem, but g++ sometimes says "out of memory". One possible error is not having the correct makefile, thus not remaking all files properly. When using templates, you should add the name of the template file (both .h and .cpp) as dependencies.
For example, suppose main.cpp uses an ArrayList of Robots.
main.o: main.cpp SortedList.h SortedList.cpp Robot.h
This is one of the rare circumstances where you need to have a .cpp file as a dependency. After all, if it changes, then main.cpp needs to be recompiled. There's no linking with SortedList.o, so that's why main.cpp needs recompiling.
No. However, I will minimize the number of tests that have robots with last names other than "Robot". Robot names and player names won't be the same, however.
No. In fact, you should write it once. Thus, if you're writing
a copy constructor for Node, it should NOT
look like:
template <class Data, class Key>
SortedList<Data, Key>::Node<Data, Key>::Node( const Data & in )
but should INSTEAD look like:
template <class Data, class Key>
SortedList<Data, Key>::Node::Node( const Data & in )
Notice, in the second case, there's only one <Data, Key>
after the template header line (the template header line is
the first line).
Because some people have decided that "SortedListDriver" should work with "Player" while some have decided that it should work with "Player *". So, I don't care which one you use. It doesn't matter whether "SortedList" works with the driver, or if it doesn't. "SortedList" should work with your code (Part 2, of Project 1).
However, "ObjSortedList" should work with the driver, and that should store objects.
You should compare pointers. Recall from the first exam that iterators are basically pointers. When you test equality of iterators, you should be testing the equality of pointers. When you use less-than, you should be comparing relative positions of iterators in a list.
The compiler is able to find errors more easily in those files (since the types are specified). If you do a good job of debugging there, then it should be better in the
That has been corrected. Make sure it's corrected in your files. Otherwise, there may be complaints by the compiler. How can you check? Currently, changes are made to the .h files by putting a date and the correction. You can "grep" for "Oct" in all header files and see what's been modified.
You certainly are! The idea is to get rid of (most of) STL from your code (except strings). You will put in ArrayList to replace vector and SortedList to replace the doubly linked list used in PlayerList (which is now Team).
My suggestion is to get your code working with the project 1 primary input, then make the new changes to produce the project 2 primary output. The changes for the project 2 primary output ought to be quick, if the code you've written isn't too buggy. You can essentially make Robot look like Player.
Very carefully. Actually, the conversion isn't too bad.
Your class declaration for Team should look something like:
class Team {
std::string teamName;
SortedList<Player *, Name> team;
public:
// add...
// remove...
};
Most of this class requires you pass the work onto the sorted
list. For example, when you want to add a Player to a
Team, you no longer traverse the doubly linked list.
Instead,
bool Team::add( const Player &player ) {
return team.add( player );
}
You can do similar things for size(), clear(),
remove(), etc. The hard part (which isn't so hard) is
converting the iterators. I suggest writing methods like
cfirst(), first(), cend(), end(), etc.
and then returning the iterators from the SortedList data
member.
No. Never.
(It's already being included in the .h file, when you #include the
.cpp in that file).
Basically, SortedList either works with pointers, or it works with objects, but it doesn't seem to work with both. Why? Think about "add". It passes in an object. It calls "getKey()" on that object. If you have a SortedList of real objects (not pointers), then you would use something like "obj.getKey()". However, if you had a SortedList of pointers, then, the compiler will complain about "obj.getKey()" saying that you can't use "." (dot) with a pointer.
So, what's the solution? The simple solution is to adjust SortedList to either handle pointers or objects, depending on which one you've used for Team. This usually is a simple matter of replacing "." with "->" whenever accessing the key.
In the meanwhile, I need a way of testing your SortedList and would prefer not to have to create two different test drivers. So, just copy your SortedList to ObjSortedList and make ObjSortedList work with the driver ObjSortedList.cpp.
Then, you can do whatever you want with SortedList so that it works with your project (provided it is still a template class for doubly linked lists).
You comment it out when you are compiling SortedList.cpp. Why? Because if you #include "SortedList.h" in #include "SortedList.cpp" and don't comment out the statement #include "SortedList.cpp", then there will be TWO copies of #include "SortedList.cpp" and the compiler will say every method is "multiply defined".
Once #include "SortedList.cpp" compiles correctly, then uncomment. From then on, you WILL NOT LINK IN SortedList.o into your p2 executable. Why? Because the compiler will complain if you do (I don't know why). However, that's not a problem because when, say, Team.cpp needs a SortedList<Player *, Name>, then not only does it get the class header (what's usually in the .h file), but also the entire implementation (because the .h file includes the .cpp file).
Yes, it's not a very pretty solution, but that's one way to do things with templates (see the book).
First, a few date changes. The early date will be October 13 at midnight. The regular due date will be October 15 at midnight.
Second, I've added a few SIMPLE drivers. I would test them more extensively, obviously (write stuff that tests copies, deletes, etc). Also, I've added <Algorithm.h> to write your own sort routine. Pick any sort routine you like. Since it was quick, I implemented using selection sort. I suggest you implement it without templates first, and then with templates (perhaps on an array of int's). Write your sort routine, using pointers, instead of array indexes, and you will find it easier to convert to iterators.
For the sort214 method, you need to call the method as:
sort214<Item>( list.first(), list.end() );where <Item> can be replaced by whatever the ArrayList is holding.
I will be posting the new primary input soon. Since it's being posted so late, I will be reducing the number of additional commands to support. In fact, so far, there are no new commands, only commands that now apply to Robots. However, the next project should have additional commands.
I like people to write private helper methods. So, you can ALWAYS, ALWAYS, ALWAYS write private helper methods. However, you may be restricted in the following areas:
The restrictions will depend on the class. You may wonder why these restrictions are placed.
This is to prevent you from including every other class in the known universe inside your class. Some people simply hate to deal with two or more objects at the same time. They want to say "In AllTeamsList, can I add the vector of Players, rooms, etc. as private data members, so I don't have to deal with them outside of the class". That has to be the poorest reason ever to put data members in a class.
However, you have to trade certain things off. For example, it may be somewhat unreasonable for a Player object to have a Team pointer to indicate which team the player is on, but perhaps not. It does make it more efficient.
Ultimately, you ask yourself "If I had to use this class to solve other problems, would this data member make no sense". Many times, data members are sensibly added, to make the class more efficient. Other times, they're added to make coding easier, even though it makes little sense other than to solve the problem at hand.
Realize that many software libraries won't let you go into their classes and modify the data members or methods just because they're inconvenient to you. While the projects given in class are not debugged to the same degree, you do need to ask yourself "should I really add this data member?". Sometimes you will say yes, and later on (possibly after the semester, when you are in a later course), you will say "what ugly code! I can't believe I did this, just to get it to work". Sometimes you will say no, and say "I really should have added it, because it would have made operations much more efficient". Sometimes, you will make a sensible decision.
Basically, the rule of thumb (for a project) is: any data member added should be "small" and support the main purpose of the class. Other than that, the goal of adding private data members is just an exercise to help you learn when and when not to add data members. (Were there enough time, I would have TAs pick a class, and have you guys critique it).
Usually, adding public methods is considered a NO-NO. If someone has already defined a class, the public methods are generally considered unchangeable. That's because you ought to think of classes as "things we will distribute to the customers who wants it". If you are the customer, and you add public methods, then others who use the class, will now have two versions: the one officially released, and your version.
While adding public methods is usually considered bad, it's usually even worse to do the next.
Unless there are errors, usually it's considered VERY bad practice to modify parameters, constness of public methods which have already been declared for you. (It's another story when you develop every aspect of the class yourself). Why is it bad? Because the reasons for changing it are often rather poor. Two reasons to change: want to get rid of constness, because it doesn't compile (due to lack of understanding of how const works) and adding more parameters for convenience.
This isn't done too often, but if people abuse it, it's because they don't want to deal with using the public methods, and would like to access the data members directly, for simplicity. Friends are to give special privileges to other classes, that most other classes don't have. Alas, there ought to be a better way to handle this kind of problem in C++ than friends.
|| You need to have BOTH Data and Key as template objects dont you? Key is a || string for Movie but will not always be a string. If you dont include key || in the template then how will you return ket when you do a getKey()? || || std::string getKey() const; || template|| Key getKey(); || || Do you always expect key to be a string??
No, it doesn't always have to be a string. Nevertheless, you only have to declare Movie as the only object in the MovieSortedList::Node. Why? Because at some point, you will call getKey() on the Movie object. It will have to return a key. It's that key which will be Key. Thus, the Key is stored inside the Data object.
class Movie {
std::string title; // THIS IS A KEY
};
The template header will still take two parameters (Data and Key), but
you DO NOT need to do:
class Node { // Nested class
Movie movie;
string title; // NOT NEEDED---the title is in Movie
Node *prev, *next;
};
You CAN if you want. If you call getKey(), it will
have to get the key from the Movie. Yes, the Movie
will return a string, but when you templatize it, it will become
whatever type the object has for a getKey() method,
provided that you specify the Key parameter type to
match what the getKey() returns. (For example, if you
have a Foo object that has a getKey() which
returns a Bar, then you should specify SortedList
to have Data as Foo and Key as Bar.
You will create a new class called Team. This is meant to replace PlayerList. Team will contain two data members: SortedList<Player> and the team's name (a string). The rest of the methods should be the same as PlayerList, except ask yourself if it's necessary to write copy constructors, assignment operators, etc. Most of the work in PlayerList will then have been put in SortedList. Basically, you will have methods like add, remove, which will then call those methods on the "team" data member.
No. I originally had it that way, but decided it didn't make too much sense. Alas, it was still in the driver afterwards. The driver has been fixed (of course, it would have been far more elegant had I known, when I wrote it, that you could overload the -> operator).
ArrayList.h is the template class version of MovieArrayList.cpp. There is also Parser.h which consolidates (puts together) several different files into one file.
You will need to write a "sort" that takes ArrayList iterators. I will provide a file called Algorithm.h and you can put your sort algorithm there. Pick any sort algorithm you want (it should be "in place", i.e., not require an additional array).
I would suggest the following strategy.
Yes, you do. These have been added to the project description. You also need to rename "PlayerList" to "Team", and have "Team" include a SortedList<Player> data member as well as a team name data member.
Just #include "SortedList.h", but don't compile SortedList.cpp nor link it. Just compile any classes that use the template class, but not the template class itself (at least for the time being).
You need to comment out the #include "SortedList.cpp" at the end of #include "SortedList.h when you are compiling. Once it works, you can uncomment it back out.
Basically, the problem is that SortedList.cpp is included twice if you don't comment it out.
This is an iterator which points to NULL. You can use it to determine when an iterator has gotten past the end of list. Alas, once the iterator has gone past the end of the list, you can't go back onto the list by using operator--.
As described in the project, Data will be Movie and Key will be a string. Notice that there's no need to have TWO data members in the template class. You just need to have one data member, which is the Data object. That object must have a getKey() method, which will return back the key (for the movie, that's the title).
Implement MovieSortedList first. Then, convert it to SortedList after that.