Purpose
The purpose of this lab is to review and develop basic skills in the
programming of C++ derived and container classes.
Acknowledgement
This lab was developed by Dr. Henry
Welch.
Preparation
Review your course materials from CS183 that pertain to the C++ mechanisms
for base classes, derived classes, inheritance, and the use of the
STL.
You may find it helpful to refer to a
polymorphism example I developed
for my CS183 students. In addition, a glossary is
provided.
Background
The field of computer graphics lends itself quite well to the use of base
classes and derived classes. The ability of derived classes to inherit
properties from a base class so that they do not have to be rewritten is
quite powerful. In addition the ability to override and customize methods
from the base class and to add new methods allows a derived class to customize
itself for its own needs.
The files shape.h and
shape.cpp declare and implement a base class called
shape that might be appropriate for generic
graphical shapes. It contains the following methods:
| Method |
Description |
| Constructors |
The usual host of constructors:
No Argument
Copy
Assignment = |
| Destructor |
For removing dynamic data components |
| Draw |
Asks the shape to draw itself in a graphical area |
| Read |
Reads a shape from data file |
| Write |
Writes the shape to a data file |
| Xform |
Transforms the shape |
| Clone |
Allocates a new shape object, copies the current object, a returns
a pointer to that object |
A quick review of the code shows that it is very much a skeleton for
what is needed to truly implement a shape. We will be using the shape class
primarily as a convenient class type in which to refer to all
shapes that have been derived from this class. As you progress through CS321
you may find it necessary to add new methods to the shape class or modify
the existing ones.
The file image.h contains part of the declaration
for a container class designed to hold pointers to shapes. By having it
hold the base class shape pointer we can in effect have it contain any
derived class shape pointer as well. Further, if we use the STL to build
our data structure we must remember that it will only be storing copies
of the pointers and not the objects themselves. In effect we will be
requiring that all shapes must be allocated on the heap (via
new) and that once added to the container
the container will take responsibility for managing and deleting them
in its destructor since the STL object will only delete the copy of the
pointer.
The methods for this class are listed below.
| Method |
Description |
| Constructors |
The usual host of constructors:
No Argument
Copy
Assignment = |
| Destructor |
Delete all the shapes from the container (the STL destructor
will not do this) and delete all other dynamic
objects. |
| Add |
Add a new shape pointer to the container |
| ReDraw |
Ask all the shapes to redraw themselves |
| Write |
Output all the shapes to a data file |
| Read |
Read a set of shapes from a data file (see below) |
| Xform |
Modify all the shapes in a image the same way |
| Zoom |
Zoom in on an image |
| Unzoom |
Zoom out on an image |
| Reset |
Revert an image to its "original" state |
| Erase |
Remove all the shapes from an image |
By organizing things within a container class it will make it easier
for other objects to conveniently manipulate an image. Again the methods
are defined in a rather sketchy form since we as yet do not know exactly
what information will be needed to implement the various methods in a real
graphic environment. You can expect to add and modify this class throughout
the term. You will notice that the data members have been left entirely
up to you. One of the goals of this assignment is to have you choose an
appropriate
STL
type for storing shapes. You may find that there are better choices than
the vector or list.
Of all these methods the Read method may turn out
to be the most difficult to implement. In most cases C++ can automatically
pick the proper virtual method for derived class objects. All of this
presupposes that the type of object is already known and created. When
reading an object from a file or the terminal we do not know what kind
of object we have until after we begin reading it. This presents somewhat
of a dilemma. There have been a number of suggestions on how to solve this
particular problem and often revolve around a special set of classes called
factory
or foundry classes. This is a nice abstract way to do this, but you may
be able to approach the problem in a simpler fashion. Essentially each
shape should contain a type field (see the QEvent
as one example) which should always appear first in the data file. The
Read method in this case will have to input the
type field and then use a construct like the switch-case to determine which
type of shape it is to create and then input. This requires that the
container class Read method
be updated every time we create a new kind of shape. Typically then, the
factory class's job would be to do this for the container class and thus
isolate the container class from this level of detail.
Laptop Linux Users
The instructions below are designed for students using their concord
accounts. If you would prefer to conduct this lab assignment on your laptop,
please follow these steps:
- Log on to concord
- Open a shell window (black screen in menu bar)
- Type ssh concord.msoe.edu and then
log in
- Change to the following directory:
/usr/local
- Make a tar archive of the cs321 directory by typing:
tar -zcvf ~/cs321.tar.gz cs321
- Log off of concord
- Change to the following directory on your laptop:
/mnt/win_d
- Transfer the file to the laptop:
sftp concord
get cs321.tar.gz
quit
- Untar the file by typing:
tar -zxvf cs321.tar.gz
- Change into the cs321 subdirectory.
- Save the following files in the cs321
subdirectory:
shape.h,
shape.cpp,
image.h, and
Imakefile
- Edit the Imake.tmpl file changing the first
line in the file from:
#include "/usr/local/cs321/Imake.rules" to
#include "/mnt/win_d/cs321/Imake.rules
- Edit the Imake.rules file changing the
line in the file from:
INCLUDES = -I$(INCD) -I/usr/local/qt-2.3.0/include/ to
INCLUDES = -I$(INCD) -I/usr/lib/qt2/include/
and the line:
LIBS = -L$(LIBD) -L/usr/local/qt/lib/ -lqt -lcs321 to
LIBS = -L$(LIBD) -L/usr/lib/qt2/lib/ -lqt -lcs321
- Clean out the old binary files by typing:
rm lib/* obj/*
Lab Activity
For this lab assignment you must do the following:
- Derive at least two different classes from the
shape class. (point and line are two simple
ones that you will need later.) Have each contain different data
members and different versions of the virtual methods. Implement all
of the member functions. (For Draw just have
a suitable message sent to cout and have Xform
make some change to derived shape.)
- Implement the image container class. For now
have Zoom, Unzoom,
and Reset do nothing. Have
ReDraw call all the shape
Draws and Xform
call all the shape Xforms.
- Develop a testing program which instantiates at least one
image object and then adds a mix of the
derived shapes to the container. You may find that a small menu-driven
approach works best. Test all of the methods to make sure they work
correctly.
- Maintain a log of your activities so that you can document how you are
spending time on this lab assignment. When you are done you should be
able to report on how long you spent on each aspect of the assignment
from planning to design to implementation, documentation and testing.
- You will find it useful to use a Imakefile
with the following Imake Imake template to
compile and link your code. (i.e. Copy these two files
to your working directory, edit the Imakefile to
reflect your file names and then execute the commands
imake and then
make lab2.) There is more information on
imake available from the Wisconsin
Regional Primate Research Center (no... I'm not joking).
Lab report (due 11pm, the day prior to week 4 lab)
Your lab report should be self-contained. That is, it should be possible
for someone to understand what you did and why without seeing anything other
than your report. Your report should include:
- Purpose
- Problem Statement
- Procedure -- what approach you used to solve the problem
- Discussion including:
- An explanation for your choice of STL container for the image
class. Be sure to identify the strengths and weaknesses of your
choice and sell me on your decision. Also explain
how you solved the container
Read problem discussed above.
- A description of your two derived shape classes so that someone else
could understand what they are used for.
- A tally of the number of Non-commented new Lines Of Code (NLOC) written
for this lab assignment. You should use the
CLC
perl script on your code.
Note: The first line of the file should be:
#!/usr/bin/perl. It will report how many lines and
statements of code you wrote. NOTE: For accurate
results you should run it on the provided code first and then subtract
that since you didn't write that code.
- A summary of your activity log indicating how much time you spent
on each phase of the assignment. Please report the time in the
following categories:
- Designing
- Coding
- Debugging (before you think it's working)
- Testing (after you think it's working)
- Report writing
- Other
- A narrative describing any specific problems you encountered and how
you solved them.
- Conclusions (what you learned, suggestions of how the lab could be
improved, things you would have done differently, etc.)
- Documented source code
You may wish to use gensrc, a shell script which
will produce an XML document that may be used as a starting point for
your report. The file will include all of the source code files
(provided you modify the script appropriately... edit gensrc for
details on how to do this.)
As with any report you submit, correct spelling
and grammar are required. In addition, your report should be submitted
electronically following the Electronic
Submission Guidelines. (You may wish to consult the
sample report before submitting your
report.) Be sure to keep copies of all your files, in case something
gets lost. It may be wise to keep a diskette backup as well.
If you have any questions, consult the instructor.
Glossary
You may find some of these terms useful in reviewing derived classes and
inheritance.
- Abstract Class- A type of class with pure virtual
member functions that behaves as a base class but prohibits the
instantiation of any members of that class. It is used to take
advantage of inheritance yet prohibiting the generation of objects
that are not completely defined.
- Base Class - A class from which other classes are
derived. It usually provides a more generalized framework of data
members and functions that are needed by all similar object.
- Derived Class - A class that is obtained by
inheriting data members and functions from a base class. A derived
class usually adds specialization to a base class.
- Inheritance - A mechanism where a derived class
object also has the same data members and functions as an object
from the base class from which the derived class was derived. NOTE:
Constructors, destructors, and overloaded functions are not inherited.
Additionally the base class constructor is always called before the
derived class constructor and the base class destructor is always
called after the derived class destructor.
- Overloading - The creation of multiple functions
with the same name yet dissimilar calling arguments (signature).
This allows for the reuse of an appropriate name for multiple
circumstances.
- Overriding - When a derived class declares a member
with the same name (the same signature is not
required) the base class member is overridden and cannot be called
directly from the derived class. This is common with virtual
functions, but is not restricted to them. Care should be taken though
when upcasting since a non-virtual overridden function will result
in the base class version being called.
- Polymorphism- The mechanism where an upcast version
of a derived class object automatically finds the versions of member
functions that are appropriate for the derived class.
- Private - A designation for class members so that
they are only accessible from member functions of that class or
friends of that class.
- Protected - A designation for class members so
that they are only accessible from member functions of that class,
member functions of derived classes, and friends of that class.
- Public - A designation for class members so that
they are accessible by anyone.
- Pure Virtual - Any virtual member function in a
base class which is declared =0 is said to not exist. (i.e., no
definition will be provided.) Any class with pure virtual data
members is an abstract class.
- Slicing - When derived class objects are passed
to functions and returned from functions as objects of the base
class the extra derived class members are removed. This can be
avoided by only passing derived class objects as pointers or as
references. This way the entire object is passed not just the base
class components. Due to limitations of the STL we will be using
pointers to avoid this.
- Static- A designation for class members that indicate
that this member is shared by all objects of that class.
- Upcasting - The action of referring to a derived
class object as if it were an object of a base class. When doing
this be sure to avoid slicing.
- Virtual - A designation for class members that
indicates that when a member of an upcast version of derived class
object is accessed it uses the derived class version not the base
class version.
|