CS 150 - Intro to Programming - Fall 2001
Lab Exercise 12

Topics:

Part 1 - The Square Class

Consider the following two files that declare (square.h) and define (square.cpp) a class named Square. The Square class includes one floating-point data member, side, in the private section which holds the state of the object. The class also has an accessor member function for accessing the value of side, a mutator (modifier) function for setting the value of side, and a member function for calculating the area.

Notice the member function prototype statements appear in the public section of the class declaration. This declares them as member functions of the Square class. Notice further that the member function definitions have direct access to the state (private data members) of the object, so there is no need to pass the side of a Square object to the member functions. Also note the scope resolution operator (::) in the .cpp file. This operator tells the compiler which class a member function belongs to.

// square.h
// Specifies general square class

class Square
  {
  public:  //Member functions
    void setSide();   // Initializes a square to a user specified size
    double getSide(); // Returns width of the square 
    double area();    // Returns area of square 

  private: //Data Members
    double side;   // square width
  };


// square.cpp
// Implements member functions of class Square

#include <iostream>
#include "square.h"

using namespace std;

void Square::setSide()    //Initialize a square to a user specified size
  {
  cout << "Enter the width of the square: ";
  cin >> side;
  cout << endl;
  } 
        
double Square::getSide()  //Return width of square
  {  return side;  }
                
double Square::area()     //Return area of square
  {  return(side*side);   }

  1. Create a project (yourLastNameLab12). Create a new file named square.h. Type in (or copy/paste) the Square class declaration as it is given above. Be sure not to miss the semi-colon after the closing curly-brace. Save the file in the project folder.

  2. Create a new source file and save it as square.cpp in the project folder. Type in (or copy/paste) the member function definitions above. Add square.cpp to the project.

  3. Create a new source file containing the following main function. Save the file as yourLastNameLab12Part1.cpp and add it to your project (be sure to remove hello.cpp). This main declares two square objects, sends a message to each object by calling the appropriate member function to set their state, outputs the square width, and displays the area of each square.
    // main.cpp
    // Driver to demonstrate square class
    
    #include <iostream>
    #include "square.h"
    using namespace std;
    
    int main()
      {
      Square sqr1, sqr2;
    
      sqr1.setSide();
      sqr2.setSide();
    
      cout << "The width of sqr1 is: " << sqr1.getSide() << endl;
      cout << "The width of sqr2 is: " << sqr2.getSide() << endl;
            
      cout << "The area of sqr1 is: " << sqr1.area() << endl;
      cout << "The area of sqr2 is: " << sqr2.area() << endl;
            
      return 0;
      }
  4. Enable the debugger and step through the execution of the program. Be sure to step into the member function calls and to examine the objects and their values.

    The this entry in the variable window of the debugger during the execution of a member function refers to the calling object. Tipping it down will uncover the data members of that calling object.

  5. Add a new member function named perimeter() that returns the perimeter of a square. To do this, you will need to modify the Square declaration in square.h by adding the prototype and add the perimeter function definition to the Square implementation file in square.cpp.

  6. Add statements to the main function to display the perimeter of each square. Run the program and verify its correctness. Save all three files in your project folder.


Part 2 - The BankAccount Class

Now we will examine another example of a programmer-defined classes. The files bankAccount.h and bankAccount.cpp (given below) define a class named BankAccount. This class is nearly identical to the one developed in Section 6.2 of the text. This version has an additional member function, deposit and is separated into two files - a header file and an implementation file. We will implement and then modify this class.

  1. Create a new CodeWarrior project. Open a new file and save it in your project folder as bankAccount.h. Type in (or copy/paste) the BankAccount class declaration as it is given below. Be sure not to miss the semi-colon after the closing curly-brace. Save the file.
    #include <iostream>
    
    using namespace std;
    
    //Class for a bank account
    class BankAccount
      {
      public:
        void set(int dollars, int cents, double rate);
        void set(int dollars, double rate);
        void update();
        void deposit(double amount);
        double getBalance();
        double getRate();
        void output(ostream& outs);
           
      private:
        double balance;
        double interestRate;
    
        double fraction(double percent);
      };

    Look at the private members of BankAccount class. There are two data members called balance and interestRate. The third private member is a function called fraction. Since fraction is a private member function, it cannot be called in the body of main or in the body of any function that is not a BankAccount member function. Function fraction can only be called in the definitions of other BankAccount member functions (Notice how it is used below).

  2. Create a new source file, save it as bankAccount.cpp in your project folder and add it to your project. Type in (or copy/paste) the BankAccount member function definitions as given below.
    #include <iostream>
    #include "bankAccount.h"
    
    using namespace std;
    
    void BankAccount::set(int dollars, int cents, double rate)
      {
      balance = dollars + 0.01*cents;
      interestRate = rate;
      }
    void BankAccount::set(int dollars, double rate)
      {
      balance = dollars;
      interestRate = rate;
      }
    void BankAccount::update( )
      {  balance = balance + fraction(interestRate)*balance;  }
    void BankAccount::deposit( double amount )
      {  balance = balance + amount;  }
    
    double BankAccount::fraction(double percent)
      {  return (percent/100.0);  }
    
    double BankAccount::getBalance( )
      {  return balance;  }
    
    double BankAccount::getRate( )
      {  return interestRate;  }
    
    void BankAccount::output(ostream& outs)
      {
      outs.setf(ios::fixed);
      outs.setf(ios::showpoint);
      outs.precision(2);
      outs << "Account balance $" << balance << endl;
      outs << "Interest rate " << interestRate << "%" << endl;
      }
    
  3. Next write a driver to test it out: Create a new source file containing the following main function. Save the file as yourLastNameLab12Part2.cpp and add it to your project.
    #include <iostream>
    using namespace std;
    
    #include "bankAccount.h"
    
    int main( )
      {
      BankAccount account1, account2;
      double depositAmount;
       
      cout << "Start of Test:\n";
    
      account1.set(123, 99, 3.0);
      cout << "account1 initial statement:\n";
      account1.output(cout);
    
      account2.set(100, 5.0);
      cout << "account2 initial statement:\n";
      account2.output(cout);
    
      account1.update( );
      cout << "account1 after update:\n";
      account1.output(cout);
    
      cout << "How much do you wish to deposit? ";
      cin >> depositAmount;
      account1.deposit(depositAmount);
      cout << "account1 after deposit: \n";
      account1.output(cout);
        
      account2 = account1;
      cout << "account2:\n";
      account2.output(cout);
        
      return 0;
      }
  4. Compile and run the program. Enable the debugger and step through the execution of the program. Be sure to step into the member function calls and to examine the objects and their values.

  5. Add a new public BankAccount member function named withdrawal with the following prototype:
    void withdrawal(double amount);
    //Postcondition: amount is subtracted from the account balance.

    Again, you will need to modify the BankAccount declaration in bankAccount.h, and also add the withdrawal function definition to the BankAccount implementation in bankAccount.cpp.

  6. Add statements to the main function to perform a withdrawal from account1. Run the program and verify its correctness.

  7. Objects of class BankAccount currently allow negative withdrawals and deposits, and withdrawals greater than the available balance. Currently there are no preconditions stated (unless you were wise enough to foresee this problem), and without safeguards, a withdrawal of a negative amount actually increases the balance and a deposit of a negative amount reduces the balance. In this step, you are asked to modify the BankAccount class to prevent these practices.
    1. Devise some test cases including both proper and improper operations. Be sure to include a negative deposit, a negative withdrawal, a positive withdrawal that is greater than the account balance, a positive withdrawal that is less than the balance and a positive deposit. Add the tests to the main() to verify your predictions.

    2. Open bankAccount.h and modify the postconditions of the withdrawal and deposit member functions. This documentation should state that deposit amounts less that 0 will not affect the balance as a result of a call to deposit and that withdrawal amounts less than 0 or greater than the current balance will not affect the balance after a call to withdrawal. (we will actually implement this fix in the next step.)

    3. Open the implementation file bankAccount.cpp and locate the deposit member function. Modify the function definition to prevent any negative amount from changing the account balance.

    4. Finally, modify the withdrawal function definition to prevent any negative amount or amount exceeding the balance from changing the account balance.

  8. Execute the modified program and verify that improper transactions are no longer taking place by noting that the balance is unaffected.

  9. The withdrawal and deposit member function are currently implemented as void functions. They do not return a value. In this step, these functions will be changed to return a bool to indicate failure or success of the operation. This makes it possible to use calls to these functions as logical expressions. For example, the calls made to these functions could be used in an if-else statement such as:
    depositAmount = -100;
    if ( account1.deposit(depositAmount) )
        cout << "Deposit succeeded. \n";
    else
        cout << "Deposit failed. \n";
    cout << "account1 balance after deposit of " << depositAmount << account1.getBalance();

    Open bankAccount.h and modify the class declaration so that deposit and withdrawal return bool values. Modify the postconditions to indicate that when the functions return 0 or when a 1 is returned.

  10. Modify the function definitions in bankAccount.cpp so that true is returned for non negative amounts and withdrawal values not greater than the account balance. If an improper amount is passed, return false.

  11. Modify the main function to use if-else statements as shown in step i. Verify its correctness using the tests developed in step g.

What to turn in