Assigned | Saturday, November 29th |
---|---|
Program Due | Tuesday, December 9th by 11:59pm |
Weight | 11% |
Updates |
|
To gain experience:
This project is considered an CLOSED project. Please review the open vs. closed project policy before beginning your project.
Being the last project, there will not be any extensions with penalties for turning this project in late. It absolutely must be submitted by the due date/time, or you will receive a 0.
In Project 4, you designed and implemented support for a collection
of document types as a C++ class hierarchy,
to take advantage of the reusability that inheritance affords.
In this project, you are going to redesign and augment the work from
Project 4, to implement four improvements. First, you will be
restructure Project 4's code to make it simpler and clearer,
as well as more flexible, by taking advantage of the even more
powerful mechanisms of late binding and polymorphism. Second, you
will add a new command to the system: "respond", that lets you reply
to emails, send a follow-up memo, etc..
Third, to see how well the existing document hierarchy supports
extensibility, you will add a new class to support an additional
document type: (TechReport
). Last, you will integrate
exceptions into your classes to better control error-handling.
For Project 4, we provided a description of the features of the various
document classes you would need, and left the design of the class hierarchy
up to you. (In this document, "document classes" refers to the base class
Document
, and all the subclasses derived from it,
like Email
and Report
.)
For this project, we have selected a specific hierarchical structure
for you to use as the basis for your own implementation.
In the provided hierarchy, we still have Document
as the base class, with Report
being directly derived
from Document. However, Email and Memo are now derived from a new
intermediate class called Correspondence
, which is derived
from Document. This allows us to
abstract out those commonalities between Email and Memo that are not shared
with Report. The Correspondence is never meant to be instantiated.
The new hierarchy looks like this:
Document /\ / \ / \ / \ Correspondence \ /\ \ / \ \ / \ \ / \ \ Email Memo Report | | | TechReportWe have provided class definitions that implement the above basic structure. The specific files are described below.
Also note the relationship of the new document type TechReport
,
which is directly derived from Report. This will be described in more
detail later.
DocumentStore
ClassFor this project, as for the previous one, we will be providing the driver program, as well as an implementation of the DocumentStore container class. The new DocumentStore class is much improved from the version we provided in Project 4, in the following ways:
type
field in the game instance to decide
which of several member functions to call, but instead lets it be managed
automatically by the late binding mechanism. (Incidentally, that means
we no longer need the GetType() method, nor any of the DOC_TYPE_XXXX
constants. However, the supporting fields, methods, and constants are still
defined in the various document class definitions--it is your responsibility
to remove them.
TechReport
, which you are responsible
for implementing. A command has been added for creating this new document
type (command #8).
The new polymorphism-aware DocumentStore methods are significantly
shorter and simpler than the versions for Project 4. For example,
the DocumentStore::Display()
method has been reduced from
32 to 8 lines! You should carefully study the new DocumentStore.cpp methods
to see what is expected of your new Document hierarchy of classes.
You should do the implementation of this project in four stages:
You will be adapting the code for the Email, Memo, and Report classes from
the non-polymorphic versions of Project 4.
To level the playing field among people who had varying degrees of
success in finishing Project 4, we are providing complete implementations
of those classes that the instructor wrote as his own solution for Project 4.
The provided implementation has working versions of all of the following
methods:
GetType() GetID() GetAuthor() DisplayBody() Search() DisplayHeader() GetSubject(): // only needed in Email and Memo GetRecipientName(): // only needed in Email and Memo GerRecipientEmail(): // specific to Email GetDistributionList(): // specific to Memo GetTitle(): //specific to Report
The provided document classes' implementations were designed to use simple inheritance and member function overriding, with no virtual functions, and therefore, no polymorphism. Because of this, we originally had to use lots of if/then/else-statments and complex pointer-casting (e.g., casting a Document* to a Memo*) in the methods of DocumentStore to get the compiler to invoke the correct document-type-specific method implementation.
Your job is to update the provided classes to make them fully polymorphic. Since the provided Project 5 DocumentStore class now assumes it can depend on polymorphism, it is currently incompatible with the provided Project 4 document class implementations. You will have to modify the provided document classes to use virtual functions and dynamic binding to make them work again for Project 5. This should be relatively straightforward if you understand the mechanics of how to write virtual functions. As provided, the document class implementations have most of the methods you will need for a working system already implemented, distributed amoung the various classes in the hierarchy. Your job is to possibly move some of the method definitions either higher up or lower down in the class hierarchy as appropriate, and combined with judicious use of virtual, or even possibly pure virtual, methods, maximize efficiency and code reuse among the classes. Two examples will set the tone:
DisplayBody()
implemented
independently, but pretty much identically, in each of the document
subclasses--this sounds like it might be a good candidate for moving
the multiple implementations up to a single version in a class
higher up in the hierarchy, and letting inheritance do the hard work.
(Note that we purposefully provided a not-so-well-organized
implementation, to give you opportunity for some interesting
restructuring to do in this stage.)
DisplayHeader()
method implementation needs to be
very different from one document type to another, and yet, the new
DocumentStore::ListDocuments() now invokes DisplayHeader() on a
generic Document pointer.
So, you must have the correct placement of virtual function declarations
among the various parent and child document classes to make this work,
e.g., get the system to run the Memo-specific DisplayHeader() even
though we are invoking it on a Document pointer.
You really should not have to write much new code for this part. Once you have finished this adaptation, you should be able to compile the full program to see if the new polymorphic logic works properly. (Ignore the compiler warnings about "function returning non-void"--you'll fix those later in the next stage.) As long as you don't try to respond to a document, or to create a technical report document type (we will fill these in in the next few stages), the program should be otherwise completely functional.
One last note: if you do not modify the logic of these functions to any significant degree from what we provided, you do not have to add documentation for the functions we are providing. However, you do have to fully document any functions you modify or add. You also must fully document any new classes you create, in particular, the TechReport class, described later.
CreateResponse()
method[This stage, and the next stage--creating the TechReport class--are actually closely related, so you should read through both sections before thinking about the design for either.]
This stage is where you will do the bulk of your new coding.
We want you to extend the various document classes to support the
new functionality of being able to respond to existing documents.
This method is called CreateResponse()
, and we have
written in a non-virtual "stub" (an incomplete version of the method that
doesn't actually do anything) into each of the provided document
classes. Your job is to flesh out these stubs with real code,
according to the specifications below.
This method needs to be supported by every concrete
(i.e., non-virtual) document class, even if that support merely
consists of always throwing an exception.
In most normal cases, this method will create a new dynamic object of the
same class as the document being responded to, and return a pointer to it.
Since the CreateResponse()
method is called polymorphically from
DocumentStore::Respond()
on a pointer of type
"Document *
", you must make this work by also adding the correct
type of declaration for CreateResponse() at the appropriate place(s) in your
document class hierarchy. Think about whether a virtual or pure-virtual
method would be best.
Your job is to add a type-specific implementation to each of the actual
real document classes: Email, Memo, Report, and later, TechReport.
The logic is differently for each of these classes, as outlined here:
In the case of a successful response, this method will usually return a
dynamically-allocated
document object, of the same type as the document being responded to, but
some document types will implement "response" by modifying the existing document
in-place (specifically, TechReports--see below) . If a new document
is created by CreateResponse(), it should return a pointer to that
response document; otherwise, it should return NULL. The calling function,
DocumentStore::Respond()
, passes in the new unique document ID that should
be assigned if a new document is in fact created, and watches the
return value to determine if the ID was actually used for a new document,
this being signalled by a non-NULL return value. In that case,
it will add the newly-created response document to the active list,
and increment the next-assigned ID.
For Email or Memo, in the case where the prospective author was rejected, you must throw an exception--this is covered in more detail in the next stage--with the message "non-recipients cannot respond." For the case where the user is trying to respond to a Report (which is never allowed), the same exception type should be thrown, but with the message "cannot respond to a report". Note that due to the way our classes are structured, since DocumentStore::Respond() collects the response body, but the document class's CreateResponse() does the validity-checking, the program will not get to complain about bad authorship until after the text is already entered; this is a small design flaw in our system--ah, well...
Note that the command-line interface has already been augmented to handle the additional document type and new commands, so there is nothing to do there.
BadResponseException
)
in the case where the request was rejected for one reason or another
(detailed in Stage 2 above).
Like the exception class examples we covered in lecture, BadResponseException
should have a data member that can store an error message string, and
also provide an accessor method called GetMessage()
to get that string out, as well as a
1-argument constructor that takes the message string as a parameter.
The implementation of DocumentStore::Respond() already assumes the document object might throw this exception, and has wrapped the call to CreateResponse() with a try/catch block--examine that code to see what your BadResponseException needs to implement.
The last task will be to write the TechReport class. The versions of the files TechReport.h and TechReport.cpp that we provide are skeletal, actually mostly just documentation, plus just enough structure to let you compile and test your Email, Memo, and Report classes first. You must write the full class definition and method definitions. However, since the TechReport class inherits all of Report's data members and methods, only a few things need to be added or overridden. There are several things that are different about a TechReport from a plain Report, and in fact, from all the other document types:
CreateResponse()
method. However,
the behavior is quite different. In TechReport, CreateResponse()
does not create a new responce document, as it does in the other
document types. Instead, it simply adds a new comment
onto the existing document. To do this, the document's textBody is
not modified. Instead, a new instance of a Comment
class
is pushed onto a vector of comments stored in the TechReport.
(We've defined the Comment class for you, at the end of the
TechReport.h file.)
Since no new document is created, TechReport's CreateResponse()
will return a NULL, instead of the usual pointer-to-new-response-document.
This lets the caller (DocumentStore::Respond()) know that a new
response document was not created. The nextID parameter is ignored.
Comment 7 by Jane Doe:
".
The comments are separated from each other and from the body by blank
lines. If there are no comments yet, output "--No comments yet."
Refer to the sample output.
Search()
method must scan both the textBody
and all of the comments for the requested string.
Note that the comment labels (e.g., "Comment 7 by Jane Doe:")
are not part of the comments, so a search for the string "Comment"
or an author name (e.g. "Doe") should not turn up anything,
unless that string was actually embedded in the body of the original
report or one of the responses.
First, there are the provided working driver and DSS source files; these files must not be modified:
main()
Next, there are the provided non-polymorphic implementations of the document classes. You must significantly upgrade these to make them work polymorphically; however, most of your changes will simply involve moving already-implemented functions around from one class to another, and make various methods virtual.
Lastly, we are providing, for the first time, a Makefile. Study it to see how it works. If you add any new files, modifying the Makefile is easy: just add it (as a .o filename) to the line that begins "OBJS=". Also, make sure you submit the Makefile with your project, regardless of whether you modified it or not.
If you've ssh’ed into the GL servers, you can copy all of the files over directly: issue the following command at the command prompt while you’re inside your project directory:
cp /afs/umbc.edu/users/p/a/park/pub/cmsc202/fall14/proj5/* .(Note the '.' at the end of the command--that is very important.)
See the course website for a description of how your project will be graded.
We will be automating much of the grading for this project. It is absolutely essential that you do not modify any of the files that we provided to you that we instruct you not to alter. You do not have to submit these, but if you inadvertantly do, we will just replace them with our own versions before attempting to compile and run your program.
Another requirement is that your executable is called Proj5.out; be careful to preserve this if you modify your Makefile.
Before submitting your project, be sure to compile and test your code on the GL system. See the Project Compilation section of the course Projects page for details on how to compile and execute your project on GL.
Assuming you’ve used the specified file names, submit your project by typing the command
submit cs202 proj5 [all of your various .h and .cpp files] Makefile
See the Project Submission page for detailed instructions. Note that we require you to submit the Makefile, even if you did not modify it, because it is one of the files we allowed you to modify, so we will always use your version.
You may resubmit your files as often as you like, but only the last submittal will be graded and will be used to determine if your project is late. Also note that if you rename or remove certain files, the old versions that you submitted earlier will stay in the submit directory unless you use "submitrm" to clean them out, which you should. At the end, a "submitls" should show exactly those files that are part of your project: no more, no less. For more information, see the Projects page on the course web site.
Remember — if you make any change to your program, no matter how insignificant it may seem, you should recompile and retest your program before submitting it. Even the smallest typo can cause errors and a reduction in your grade.