CIS 330 Home Page Last updated 2008/02/08 11:09:36

CIS 330 Assignment 5

C++ Inheritance

Use the web service e-turnin to submit your work electronically. You may turn in revisions of your homework up to the time it is due.

The first two problems use the class Array, which implements a simple single dimensional array of integers, encapsulating the memory allocation, copy initialization, assignment, and array operations. Array is used as a base class in the first two problems. The code for class Array can be found in Array.h.


  1. Write a C++ class RangeArray that implements a single dimensional array of integer values. The way that this class differs from Array is that instead of zero based indexing to elements, the indexing is from a range specified to the constructor. For example, if a RangeArray object arr is constructed for the range -10 to 10, then there are 21 valid index values ranging from -10 to 10. That is, arr[-10], arr[-9], ..., arr[0], arr[1], ..., arr[10] are all valid values from the array.

    Your class RangeArray must inherit from Array and use as much of the functionality of Array as possible. Implement RangeArray in a single header file RangeArray.h which includes the supplied Array.h. You do not need to change Array.h or submit it, but your RangeArray.h must include it.

    Use the driver code rarrayTest.c to test your solution.

    Running this program should produce the following:

    a1 is [3 5 7 9 11 13 15 17 19 21]
    a2 is [3 5 7 9 11 13 15 17 19 21]
    a3 is [2 5 8 11 14]
    a2 is [2 5 8 11 14]
    r1 is [1 2 3 4 5 6 7 8 9 10 11 12]
    r2 is [23 22 21 20 19 18 17 16 15 14]
    r3 is [1 2 3 4 5 6 7 8 9 10 11 12]
    r3 is [23 22 21 20 19 18 -7 16 15 14]
    a2 is [23 22 21 20 19 18 -7 16 15 14]
    

  2. Write a C++ class GrowableArray that implements a single dimensional array of integer values. The way that this class differs from Array is that if you assign to an element whose index is larger than the size of the array, then the array automatically grows its storage to accommodate the larger index. Moreover, any values in the array that have not been set have a default value of zero. Otherwise, all of the operations of Array are possible.

    Your class GrowableArray must inherit from Array and use as much of the functionality of Array as possible. Implement GrowableArray in a single header file GrowableArray.h which includes the supplied Array.h. You do not need to change Array.h or submit it, but your GrowableArray.h must include it.

    Use the driver code garrayTest.c to test your solution.

    Running this program should produce the following:

    g is [3 5 7 9 11 13 15 17 19 21]
    g2 is [3 5 7 9 11 13 15 17 19 21 0 0 0 13 0 0 0 0 0 0]
    

  3. Write a collection of C++ classes that implement Boolean expressions. The following classes need to be defined:
    Expr
    This is the abstract base class for an expression. Common behavior of all Expr objects is to be able to print them using the standard output operator, and evaluate them.
    AND and OR
    These classes implement logical and and or. The constructors each take two Expr arguments, and they evaluate according to Boolean logic.
    XOR
    This class implements logical exclusive or. The constructor takes two Expr arguments, and the evaluation will be true if exactly one of the operands is true.
    NOT
    This class implements logical negation. Its constructor takes a single Expr argument.

    You may have various abstract classes in your inheritance hierarchy, but must at least define the abstract base class Expr from which all of your other classes directly or indirectly derive. You may find it useful to define intermediate abstract classes such as BinaryExpr or UnaryExpr to maximize code reuse.

    Each of your classes must have the method evaluate to evaluate the expression. Evaluate returns a C++ bool value, the truth value of the expression. The constructors of your classes should behave as shown in the driver code, allowing an expression tree to be built and evaluated. Moreover, your classes must also implement a mechanism for printing using iostream operators.

    The idea of this expression hierarchy is to be able to create expression trees and evaluate them dynamically. That is, the evaluate method should not be called by constructors - you should assume that in real use, the evaluation would not be known as the expressions are constructed, but only after construction. This implies that the various expression subclasses are likely to contain pointers or references to the expression objects that they are made from.

    Implement all of your classes in a single header file Expr.h.

    Use the driver code exprTest.c to test your solution. Note that the driver code defines another class, Query which derives from Expr. This class simulates the notion of a database query (and simulates the evaluation by choosing a random result value). The driver then forms various Boolean expressions of the queries and evaluates them.

    Running this program produces results like the following:

    Query1 is false
    Query2 is true
    Query3 is false
    ( Query1 ) AND ( Query2 ) is false
    ( Query1 ) OR ( Query2 ) is true
    ( ( Query1 ) OR ( Query2 ) ) AND ( Query3 ) is false
    NOT ( ( ( ( Query1 ) AND ( Query2 ) ) AND ( ( Query1 )
      OR ( Query2 ) ) ) OR ( NOT ( ( ( Query1 ) OR ( Query2 ) )
        AND ( Query3 ) ) ) ) is false
    ( ( Query1 ) XOR ( Query2 ) ) XOR ( Query3 ) is true
    
    
    The next to last line of output has been spread over three lines for this web page, but your program should produce it as one single line.

    Note: the example Query class in the driver has a clone method. Since we want to be able to create expression objects from other temporary expression objects (as in the variable e4, the temporary objects must be able to be cloned so that they persist after the temporary disappears. (And the object creating the clone will be responsible for cleanup.)