Project 4: Numeric Classes

Assigned:  8 November 2001

Homework Due:  18 November 2001

Project Due:  25 November 2001


Objective

The objective of this assignment is to practice writing C++ classes which use inheritance and polymorphism.


Background

We want to write a set of classes which will model the behavior of different types of numbers, namely rational numbers, fixed-point numbers, and complex numbers.  Each class will adhere to a common interface.

Properties of Rational Numbers

Properties of Fixed-Point Numbers

Properties of Complex Numbers

 


Assignment

You will implement the classes whose definitions are shown below.  You may add whatever private members and functions you see fit to any class; you may not change the public section of any class definition in any way (except that you may omit member function parameter names, and you need not include exactly the same comments).  We will be linking your compiled code in with our own main function for testing purposes, so you need not submit a main function definition; however, you will probably want to write one for yourself to help with testing your class implementations.

Abstract Base Class

The Number class will be a base class of the three classes described above.  It will serve to provide an interface to each of the methods that are implemented by all of those classes.  Note that the methods which return Numbers return by pointer.  This is necessary because in actuality, they will return pointers to the appropriate derived types. 

class Number
{
    public:
              virtual ~Number ( ) = 0;  // virtual destructor

              virtual double magnitude ( ) const = 0; // returns the magnitude

              virtual Number* square ( ) const = 0;  // returns the square of *this

              virtual Number* raise ( int x = 1 ) const = 0; // returns *this  to the power x

              virtual Number* scale ( int x = 1 ) const = 0;  // returns *this multiplied by x

              virtual void print ( ) const = 0;  // prints out *this in a human-readable format

    private:
               

}

Derived Classes

The Rational, FixedPoint, and Complex classes are described here.  Note that each one implements its own methods unique to that type, in addition to implementing the common set of methods specified in the Number base class.  Also, note that the methods square, raise, and scale return pointers to the derived class type, rather than pointers to type Number as declared in the base.  This is allowed in C++ because a pointer to a derived type can always be converted to a pointer to a base type.  When return types of virtual functions in a base and a derived class differ in this fashion, they are said to be covariant return types.  Note that the return type in the derived class can be a subclass of the return type in the base class, but not the other way around.  Also, the return types do not have to be identical to the classes themselves, as they are in this example.

If the default assignment operator and/or copy constructor will not be sufficient for any of your derived classes, then you must implement one.  You may also add any additional constructors of your choosing to any class; however, the constructors listed here must be implemented.

class Rational: public Number
{
    public:
            Rational ( int numerator = 0, int denominator = 1);  // constructor

            ~Rational ( );  // destructor

             Rational operator+ ( const Rational& rhs) const;  // Addition

             Rational operator- ( const Rational& rhs) const;  // Subtraction

             Rational operator* ( const Rational& rhs) const;  // Multiplication

             Rational operator/ ( const Rational& rhs) const;   // Division

             Rational invert ( ) const;  // returns the reciprocal of *this                

           // Implementations of Number methods 

             double magnitude ( ) const;

             void print ( ) const;

             Rational* square ( ) const;

             Rational* raise ( int x = 1 ) const;

             Rational* scale ( int x = 1 ) const;

    private:
               

};

class Complex: public Number
{
    public:
            Complex ( float real = 0, float imaginary = 0);  // constructor

            ~Complex ( ); // destructor

             Complex operator+ ( const Complex& rhs) const;  // Addition

             Complex operator- ( const Complex& rhs) const;  // Subtraction

             Complex operator* ( const Complex& rhs) const;  // Multiplication

             Complex operator/ ( const Complex& rhs) const;   // Division

              Complex conjugate (  ) const;  // if *this is a + bi, returns a - bi

           // Implementations of Number methods 

              double magnitude ( ) const;

              void print ( ) const;

              Complex* square ( ) const;

              Complex* raise ( int x = 1 ) const;

              Complex* scale ( int x = 1 ) const;

    private:
               

};

class FixedPoint: public Number
{
    public:
            FixedPoint ( int integral = 0, int fractional = 0);  // constructor

                                                                            // user will enter fractional between 0 and 999,999

            ~FixedPoint ( ); // destructor

             FixedPoint operator+ ( const FixedPoint& rhs) const;  // Addition

             FixedPoint operator- ( const FixedPoint& rhs) const;  // Subtraction

             FixedPoint operator* ( const FixedPoint& rhs) const;  // Multiplication

             FixedPoint operator/ ( const FixedPoint& rhs) const;   // Division

             int truncate ( ) const; // returns the integer part

           // Implementations of Number methods 

             double magnitude ( ) const;

             void print ( ) const;

             FixedPoint* square ( ) const;

             FixedPoint* raise ( int x = 1 ) const;

             FixedPoint* scale ( int x = 1 ) const;

    private:
               

};

class DivideByZero   // This exception should be thrown if any function listed above tries to divide by zero

                                //  This includes passing in a zero denominator to the Rational constructor

{

public:    

    void PrintInfo ( void ) const;  // Prints the name of the subclass and function that tried to divide by zero

private:

}

 


Homework Portion

The homework portion of this project will be worth 10% of the project grade.  For the homework, create a plain text file (end the filename in .txt) which includes the prototypes of any functions you intend to use that are not listed here, the class definition you intend to use (include private members/functions), and a one- to two-paragraph (approximately) description of how you intend to implement the member functions.  You may use pseudocode if you wish.  (This file is not intended to be compiled; it is only for you to express the design of your program.)  Your homework will be graded both on the merits of your design and on the extent to which you follow that design in the implementation of your program.  Remember to submit your homework file by the homework due date.  Late homework submissions are not accepted.


Requirements

  1. Write your program in C++, using the g++ compiler installed on the linux systems at UMBC (linux.gl.umbc.edu). Use C++ input and output, not printf and scanf.  The graders will compile your code using the -ansi and -Wall switches, so make sure to test your program with these and to explicitly specify these in your makefile.
  2. Your makefile need not produce an executable.  However, "make Rational" should produce Rational.o, "make Complex" should produce Complex.o, and "make FixedPoint" should produce FixedPoint.o, so that the graders can link in your compiled code with a main ( ).
  3. As per the syllabus, your project must compile (under the above-mentioned compiler) in order to receive credit.  See the syllabus for more details.
  4. You must follow the course style guidelines listed on the course web page.
  5. Write and submit separate header and class files, as discussed in lecture.
  6. When designing your program, pay attention to the design considerations discussed in class.
  7. Be sure that in your class definitions and implementations, you have spelled the names of all public member functions listed above, and the name of the class, correctly!  Failure to do so will cause your code not to link properly with the main function used for grading.
  8. Some students have asked if they will be allowed to use the setprecision function.  This is not applicable to the FixedPoint class, since this class is made up of two integers.  Storing a FixedPoint as a floating-point number will cause a loss of precision, resulting in incorrect calculations.

 


Turning in your program

You must include the following statement in a comment section of your program:

 

I have read and I understand the course policy on cheating. By submitting the following program, I am stating that the program was produced by my individual effort.

Turn in your program using the UNIX submit utility, by using the following command at the unix prompt:

submit cs202 proj4 filename

where filename is the name of the file you wish to submit.  Remember to submit a plain text file for the homework assignment, your C++ source files for the project, and your makefile.  After entering this command, you should get a confirmation that submit was successful:

Submitting filename...OK

You can check your submission by entering the command:

submitls cs202 proj4

This will show the names of all files you have submitted for this project, along with the size and submission date and time of each.  


Late Policy Reminder

This project is due by midnight (1 minute after 11:59pm) on Sunday, 25 November 2001. We will use the system clock as the final arbiter of time and date. Projects turned in up to 24 hours late will receive a 10% penalty; project submitted between 24 and 48 hours late will receive a 25% penalty.  Projects will not be accepted past 48 hours after the due date.  Late homework submissions are not accepted.