CMSC 341 Project Organization
This document describes the project orgranization, programming style
and class design guidelines
to be used in CMSC 341. Each project will be evaluated based on these
guidelines. Failure to follow any of these criteria will result in a lower
project score.
File Organization
The organization and structure of the files for a C++ program is
important. Poorly organized files make code maintenance and debugging
difficult. Here are the rules for file organization for projects:
- Each class must be defined in its own header file. The file
extension must be .H This file must be
named after the class.
For example, class Foo would be defined in a file named
Foo.H
- Every such header file must be guarded using the
#ifndef FOO_H
#define FOO_H
.
.
#endif
style. This style is used to avoid multiple includes of the header.
- No method is to be implemented in a header file. Implementation
belongs in the matching implementation file.
- Each class is to be implemented in its own implementation file.
The file extension must be .C.
This file must be named after the class.
For example, the Foo class
would be implemented in a file named Foo.C
Note that each class has two associated files -- the definition or
header file (.H extension) and the implementation file (.C extension).
- A header file is to be included in a given file if and only if
the header defines an entity referred to in the given file.
Do include the header if it defines an entity used in the class definiton
(eg. as a private data member or method parameter). Do not include it otherwise.
For example, suppose Foo.H refers to an
ostream entity and a string entity.
Then, you must include iostream and string.H in Foo.H.
Now, suppose the implementation file Foo.C refers to an
ostream entity, but not a string
entity. Then Foo.C should include
Foo.H and iostream, but not
string.H. Note that iostream is included
even though its inclusion is also caused by including Foo.H.
Guarded header files keep this from causing multiple definition and your
code becomes cleaner and more readable.
The purpose of this requirement is to prevent dependence on the order in
which header files are included in any other file. In the example above,
if Foo.H did not include iostream, then Foo.C
will compile if and only if iostream is
included before Foo.H.
- The main function is to be in its own file.
This file must be named after the project and have a .C extension.
For example, the main function
for project 3 would be in a file named Proj3.C.
- The executable for a project must be named after the project.
For example, the executable for project 3 must be in the
Proj3 file. This is very important because the grading
script will look for that file to run your program. The script will not
run a.out or any other executable. The executable name
is controlled by your makefile - get it right. Do not submit your
executable, the grading script will construct it by using your makefile.
Documentation falls into two basic categories -- documentation for the user
of your class and documentation for the programmer.
The header file for a class presents the public interface for the
class. We adopt the convention that class documentation is done in
the header file. Implementation files must be documented also, but
this is documentation for the programmer, not for the class user.
The list below enumerates the minimum documentation requirements
for this course. The appropriate format and style for this documentation is
outlined below.
User Documentation in the header file
Documentation of a class is to include the following information:
- Every header file is to be headed by comments giving the name of the file,
your name, your section, your student ID, your GL email address,
the creation and current dates, and a brief description of the file's
contents. See the sample header file
below for an example.
- At the start of the definition, describe the class, the author
(you), and the current version (a date).
- At the start of each method describe
- The purpose of the method.
- The meaning of each parameter.
- Any pre-conditions.
- Any side effects (rare)
- The meaning of what is returned.
- Exceptions thrown (if applicable), including under
what conditions the exception is thrown
- The behavior of your method in exceptional circumstances
(if exceptions are not thrown).
For example, you may need to decide whether a public method should throw an exception or
provide some reasonable behavior when faced with invalid parameter(s). If you choose not
to throw an exception, your design decision must be documented here so that the user is
aware of your method's behavior.
For an example of class documentation, see the
sample header below. You are encouraged
to adopt this sample style. If you prefer your own style, that's ok,
but it must meet the specifications laid out here.
Programmer Documentation in the implemenation file
The purpose of this documenation is to provide the programmer who modifies
your code 6 months from now (this may be you!) a description of the code.
This description should make your code easily readable and quickly understandable by a
comptent C++ programmer.
- Every implemenation file is to be headed by comments giving the name of the file,
your name, your section, your student ID, your GL email address,
the creation and current dates, and a brief description of the file's
contents. See the sample header file
below for an example.
- Each function or method must have a header comment includes the following:
- function name
- a description of what the function does
- a description of the function's inputs
- a description of the function's outputs
- side effect of the function (if any -- this should be rare)
- "In-line" comments are used to clarify what your code does, NOT how it does it. Good comments don't repeat the code or explain it. They clarify
its intent. Comments should explain, at a higher level of abstraction
than the code, what you're trying to do.
Well structured code will be broken into logical sections that perform a simple task.
Each of these sections of code (typically starting with an 'if' statement, or a loop or a 'switch'
should be documented. A particularly important line of code should also be commented.
Do not comment every line of code. Trivial comments such as
// increment x or // end for loop
are worse than no comments at all.
There is no universally-accepted coding standard for C++ programs.
When you get that super high-paying job after graduation, you will
most likely have to work to some coding standard. Most
standards are arbitrary, but serve the important function of making
your code more readable for others following the standard. Standards
can also help in bug detection. Standards are good, but there is no
one good standard.
For projects in this class, use the following coding standard:
- Here are some suggested naming conventions. The important thing is
that your naming is consistent. Following these conventions will help
consistency. If you don't like these, adopt your own, but be consistent.
- Comments and whitespace -- The readability of code is an important, but often overlooked aspect
of good programming. For this course, we will will adopt the following
commenting and whitespace standards. The standards listed below are in
addition to those listed above.
- Prefer C++ style (ie // ) comments for in-line commenting, but C style
comments are acceptable
- All in-line comments must be above the code to which they apply
and indented to the same level. DO NOT place comments at the end of the
line. For example
// proper inline comment here
for (....)
for (...) // not here
- In-line comments tell us what the code is doing, not HOW it's doing
it
- Avoid worthless comments.
- Use 3 or 4 spaces for each level of indent. xemacs can be
configured to do this for you.
- use whitespace around all operators
- use blank lines to separate each major section of code
The following guidelines apply to all classes which you design and/or implement
in your projects for this course.
The UMBC student GL system consists of mutiple systems, some of which run the IRIX operating
system and some which run the LINUX operating system. Your programs must compile
and execute on LINUX. To be sure you've logged into LINUX, always log-in to
linux.gl.umbc.edu.
All students must use the g++ compiler in /usr/local/bin.
You should do the following to avoid using the wrong compiler
- In your project makefiles, explicitly specify the compiler as
/usr/local/bin/g++ rather than simply as g++
- Modify your .cshrc file (found in your home directory -- note the leading dot)
by adding the line alias g++ /usr/local/bin near the bottom.
To check that you are using the correct g++ compiler, execute the command which g++.
The response should be /usr/local/bin/g++
Further, the compiler switches -ansi and -Wall must be used when compiling.
These should be included in your makefile rules and used whenever you compile "by hand".
Every project must be submitted with an associated makefile. The
makefile is to be named either Makefile or
makefile, your choice. No other names are acceptable
for your makefile.
The grading script will compile your submitted project by using your makefile,
so your makefile must correctly make your project. This includes correct
naming of the executable.
A number of tutorials on makefiles are available. One is the
UCS tutorial. Another is an
excerpt from the GNU tutorial. Links to them are on the "Projects"
page of the course web page.
You can download a nice tutorial on Unix Programming Tools from
the Stanford CS Library at
http://cslibrary.stanford.edu/107/.
Note: this header file is only a sample. It is not really usable
in Project 1. Use it as a model of a well documented and correctly
organized header file.
/********************************************************
Array.H
CMSC-341 Fall 2000 Project 1
Penny Rheingans, Section 4, 999-99-9999, rheingan
Created: 1 September 2000
Current: 8 September 2000
Array ADT
An improved array that allows dynamic resizing, range checking, and
assignment to another Array. An Array "knows" its own size.
*********************************************************/
#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
template <class T>
class Array
{
public:
// Default constructor. Array size is zero.
Array();
// Construct new Array of size sz, elements unspecified.
// Param sz: the size of this Array.
// Precondition: sz > 0. If sz <= 0, Array size will be
// taken as zero.
Array(int sz);
// Construct new Array of size sz_bi with initial
// elements from bi_aray (a built-in array of size sz_bi)
// Param bi_aray: a built-in array from which to draw the
// initial elements of this Array
// Param sz_bi: the size of bi_aray
// Precondition: bi_aray must really be of size sz_bi. If
// sz_bi <= 0, an empty Array is constructed. If sz_bi
// exceeds the actual size of bi_aray, errors may occur due
// to array access boundary violations. If sz_bi is less than
// the actual size of bi_aray, initialization of the Array
// will be incomplete.
Array(T* bi_aray, int sz_bi);
// Copy constructor
// Param arr: the Array to copy
Array(const Array<T>& arr);
// Destructor
~Array();
// Accessor for size of this Array.
// Return: the size of this Array.
int getSize() const;
// Increase this Array's size.
// Param delta: the amount by which to increase this
// Array's size
// Pre-condition: delta greater than or equal to zero. This
// is enforced by an assertion.
void grow(int delta);
// Decrease this Array's size.
// Elements are removed from the right (elements from
// A[size - delta] through A[size - 1] are lost).
// Param delta: the amount by which to decrease this
// Array's size.
// Pre-condition: delta greater than or equal to zero and
// no greater than present size of this Array. This is
// enforced by an assertion.
void shrink(int delta);
// Assignment operator
// Assign ar to this Array
// Param: arr is the Array to assign (the rvalue)
// Return: this Array after modification.
Array<T>& operator= ( Array<T> & arr);
// Index operator. Retrieve element at the specified index.
// Param: indx is the index
// Return: the element at index in this Array.
// Pre-condition: 0 <= indx < size. This is enforced by
// an assertion.
const T & operator[] (int indx) const;
// Output operator
// Param: os the stream to which to write arr
// Param: arr is the Array to write
// Return: os
friend ostream& operator<< (ostream& os, const Array<T>& arr);
private:
int _size;
T* _array;
};
// for g++ templates, #include the .C file
#include "Array.C"
#endif