Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

C++ Background: In C++, many of the keyboard symbols that are used between two v

ID: 3570533 • Letter: C

Question

C++

Background:

In C++, many of the keyboard symbols that are used between two variables can be given a new meaning. This feature is called operator overloading and it is one of the most popular C++ features. Any class can choose to provide a new meaning to a keyboard symbol. Not every keyboard letter is redefinable in this way, but many of the ones we have encounted so far are, like + and - and * and / and > and <, for example. It is a class' choice to do this, so mostly it is viewed as a driver code convenience to support them. But because so many of us have an assumption that + should do addition but also perform string concatenation when working with textual data. Each operator becomes a friend function in C++ that your class can implement. The arguments to most of the operator overloads are defined as const TrashCan &. This syntax is a new kind of parameter passing called const-reference parameters. For a classtype, like TrashCan, const & signifies a read-only argument that cannot be changed by the function that receives this object. The compiler enforces this restriction and, for classes, const & simulates a pass-by-value mechanism without the overhead of copying the object, which might take a tremendous amount of time away from our program. Read the book and demo source examples carefully to see how this is done. Trust me, the first time you work with operators in C++, it is a very error-prone process. My best advice to you is to complete one operator at a time.

Project 1: Fuller TrashCan

Using TrashCan.cpp (.NET 2012 XCode ), enhance the TrashCan class so that it supports the operators +, -, < and >. A sample pile of driver code is shown below to assist you in this effort. Operators + and - should create a new TrashCan from the two arguments by combining their contents. If you wind up with a TrashCan with a size that exceeds its capacity, print out an error message. If you wind up with a negative capacity or negative size, print out an error message.   Operators < and > must return bool and should compare the holdings of the two arguments to determine which one is bigger.

My strong advice is to work one operator at a time, as these steps are very error-prone and lead to many, many compile errors.

TrashCan Class

void setSize( int size );
int getSize( );
int getContents( );
void addItem( );
void empty( );
void cover( );
void uncover( );

void printCan( );

Driver Code

#include "TrashCan.h"

#include
using namespace std;

int main( ) {

  cout << "Welcome to Howie's TrashCan Program!" << endl;

  TrashCan myCan;
  TrashCan yourCan;

  yourCan.setSize( 12 );
  myCan.setSize( 12 );

  yourCan.addItem( );
  yourCan.addItem( );
  myCan.addItem( );

  myCan.printCan();
  yourCan.printCan();

  TrashCan combined = yourCan + myCan;
  cout << "this can's filled to " << combined.getContents( ) << endl;

  TrashCan other = combined

TrashCan Class

TrashCan( );
TrashCan(int size );
TrashCan(int size, int contents );

void setSize( int size );
int getSize( );
int getContents( );
void addItem( );
void empty( );
void cover( );
void uncover( );

void printCan( );

bool myIsCovered;
int my_Size;
int my_Contents;

Explanation / Answer

Driver.cpp

#include <iostream>
#include <stdexcept>
#include "TrashCan.h"
#include <cstdlib>
using namespace std;
using namespace cs52;
int main( ) {
  
   cout << "Welcome to Howie's TrashCan Program!" << endl;


   TrashCan myCan;
   TrashCan yourCan;
   TrashCan empty( 0, 0 );
   yourCan.setSize( 12 );
   myCan.setSize( 12 );
yourCan.addItem( );
   yourCan.addItem( );
   myCan.addItem( );
   myCan.printCan();
   yourCan.printCan();

   // read in a TrashCan...
   // the class designer for TrashCan (that's you!)
   // gets to decide which fields matter and should be read in
   cs52::TrashCan sample;
   cin >> sample;

   // print out a TrashCan...
   // the class designer for TrashCan (that's you!)
   // gets to decide which fields matter and should be printed
   cout << sample << endl;


   TrashCan combined = yourCan + myCan;
   cout << "this drive's filled to " << combined.getUsed( ) << endl;


   TrashCan other = combined - myCan;
cout << "the other cup's filled to " << other.getUsed( ) << endl;


   if (combined > other) {
     cout << "looks like combined is bigger..." << endl;
   }
   else {
     cout << "looks like other is bigger..." << endl;
   }


   if (myCan > other) {
     cout << "looks like myCan is bigger..." << endl;
   }
   else {
     cout << "looks like other is bigger..." << endl;
   }

   if (yourCan < myCan) {
     cout << "looks like yourCan is smaller..." << endl;
   }
   else {
     cout << "looks like myCan is smaller..." << endl;
   }

   // let's throw some exceptions...

   try {
     empty = empty - combined;
     cout << "something not right here..." << endl;
   } catch( exception &e ) {
   cout << e.what() << endl;// an exception should get thrown...
   cerr << "Type: " << typeid( e ).name( ) << endl;// so the lines of code here should
     // be run, not the cout statement above...
   cout << "underflowing exception was caught. moving on... " << endl;
   } catch( std::logic_error ) {
     // the new kind of exception should be caught, not this one
     cout << "wrong kind of exception caught..." << endl;
   }

   try {
     empty.addItem( );
     cout << "something not right here..." << endl;
   } catch( exception &e ) {
    cout << e.what( ) << endl ; // an exception should get thrown...
     // so the lines of code here should
     // be run, not the cout statement above...


     cout << "overflowing exception was caught. moving on... "<< endl;
   } catch( std::logic_error ) {
     // the new kind of exception should be caught, not this one
     cout << "wrong kind of exception caught..." << endl;

   }

   try {
     cs52::TrashCan t( -1, -1 );
     cout << "something not right here..." << endl;
   } catch( exception &e ) {
      cout << e.what() << endl;
   cerr << "Type: " << typeid( e ).name( ) << endl;// an exception should get thrown...
     // so the lines of code here should
     // be run, not the cout statement above...
     cout << "underflowing exception was caught. moving on... " << endl;


   } catch( std::logic_error ) {
     // the new kind of exception should be caught, not this one
     cout << "wrong kind of exception caught..." << endl;
   }
  
   return( 0 );
}

Trashcan.cpp

#include <iostream>
#include <stdexcept>
#include "TrashCan.h"
#include <cstdlib>
using namespace std;

namespace cs52 {
TrashCan::TrashCan( ) {
  myIsCovered = false;
  my_Size = 0;
  my_Contents = 0;
}


TrashCan::TrashCan( int size ) {
  if (size < 0 )
  {
   throw ;
  }
  myIsCovered = false;
  my_Size = size;
  my_Contents = 0;
}


TrashCan::TrashCan( int size, int contents ) {
  if (size < 0 || contents < 0)
  {
   throw UnderflowingTrashCanException(size, contents);
  }
  myIsCovered = false;
  my_Size = size;
  my_Contents = contents;


}

void TrashCan::setSize( int size ) {
  my_Size = size;
}

void TrashCan::addItem( ) {
  if (my_Size< 0 || my_Contents< 0)
  {
   throw UnderflowingTrashCanException(my_Size, my_Contents);
  }
  my_Contents = my_Contents + 1;
}
  
void TrashCan::empty( ) {
  my_Contents = 0;
}


void TrashCan::cover( ) {
myIsCovered = true;
}


void TrashCan::uncover( ) {
  myIsCovered = false;
}


void TrashCan::printCan( ) {
  cout << "A TrashCan with a size=" << my_Size << " and containing " << my_Contents << " piece";
  if (my_Contents != 1) {
   cout << "s";
  }
  cout << " of trash" << endl;
}


/************error checking***********/


int TrashCan::getUsed( ){
  if (my_Contents > 0)
   if (my_Contents > my_Size)
   {
    return 0;
    
   }else if (my_Contents == my_Size)
   {
    return 1;
    
   }
   else
  {
    return 2;
   }
  else
  {
   return 3;
   
  }
   }

/************overloading operators***********/
TrashCan operator+ (const TrashCan& can1, const TrashCan& can2){
  TrashCan temp;
  temp.my_Contents = can1.my_Contents + can2.my_Contents;

//throwing negative value exception
  if (temp.my_Contents < 0 || temp.my_Size < 0 || can1.my_Contents < 0 || can1.my_Size <0 || can2.my_Contents < 0 || can2.my_Size < 0)
{
   //throw UnderflowingTrashCanException();
  }


//checking if pointer to object is null
  if (&temp == NULL)
  {
   throw logic_error("Your trashcan cannot be NULL!");
  }

//use the largest trashcan size
  if(can1.my_Size > can2.my_Size)
   temp.my_Size = can1.my_Size;
  else
   temp.my_Size = can2.my_Size;


  //checking for size vs. contents
  if(temp.myIsCovered > temp.my_Size){
   throw OverflowingTrashCanException(temp.my_Size, temp.my_Contents);
  }
  
  return temp;
}


TrashCan operator -(const TrashCan& can1, const TrashCan& can2){
  TrashCan temp;
  temp.my_Contents = can1.my_Contents - can2.my_Contents;
//throwing negative value exception
  if (temp.my_Contents < 0 || temp.my_Size < 0
   || can1.my_Contents < 0 || can1.my_Size <0
   || can2.my_Contents < 0 || can2.my_Size < 0)
  {
   throw UnderflowingTrashCanException(temp.my_Size, temp.my_Contents);
  }
  //checking if pointer to object is null
  if (&temp == NULL)
  {
   throw logic_error("Your trashcan cannot be NULL!");
  }


  //use the larges trashcan size
  if(can1.my_Size > can2.my_Size)
   temp.my_Size = can1.my_Size;
  else
   temp.my_Size = can2.my_Size;


  //checking for size vs. contents
  if(temp.myIsCovered > temp.my_Size){
   throw OverflowingTrashCanException(temp.my_Size, temp.my_Contents);
  }


  return temp;

  
}


bool operator <(const TrashCan& can2, const TrashCan& can3){
  //checking if pointer to object is null
  if (&can2== NULL || &can3 == NULL)
  {
   throw logic_error("Your trashcan cannot be NULL!");
  }


  if(can2.my_Contents < can3.my_Contents)
   return true;
else
   return false;
}

bool operator >(const TrashCan& can1,const TrashCan& can2){
  //checking if pointer to object is null
  if (&can1 == NULL|| &can2 == NULL)
  {
   throw logic_error("Your trashcan cannot be NULL!");
  }
  if(can1.my_Contents > can2.my_Contents)
   return true;
  else
   return false;
}

ostream& operator <<(ostream& outs, TrashCan& can ){
  
  switch (can.getUsed())
  {
  case 0:{


   return (outs << "the brim and is spilling out"); break;}
  case 1:
   return (outs << "the brim"); break;
  case 2:
   return (outs << can.my_Contents << " pieces of trash"); break;
case 3:
   return (outs << "negative number? It's a black hole! RUN!"); break;
  }
}

//overloading ostream with the option to check for NUll pointers
ostream& operator <<(ostream& outs, const TrashCan* drive){
  try{
   if (drive == NULL)
   {
    throw logic_error("You cannot have null trashcan!");
   }
   return (outs << "The size is " << drive->my_Size << endl
   << "There are " << drive->my_Contents << " pieces of trash" << endl);
}catch( logic_error &e){
   cout << e.what() << endl;
   drive = new TrashCan(0,0);
  }
}

istream& operator >>(istream& in, TrashCan& can){
  cout << "Size: ";
  in>> can.my_Size;
  cout << "Contents: ";
  in >> can.my_Contents;
  return in;
}

//overloading istream operators, if pointer to object is null, create one.
istream& operator >>(istream& in, TrashCan * &drive){
  try{
   if (drive == NULL)
   {
    throw logic_error("Your trashcan cannot be NULL!");
   }
    cout << "Size: ";
    in >> drive->my_Size;
   cout << "Contents: ";
    in >> drive->my_Contents;
    if (drive->my_Contents < 0 || drive->my_Size < 0 )
    {
     throw UnderflowingTrashCanException(drive->my_Size, drive->my_Contents);
    }else

    return in;
   
   
  }catch(logic_error &e){
   cout << e.what() << endl;
   cout << "restoring default parameter" << endl;
   drive = new TrashCan(0,0);
  }

}
}

TrashCan.h


#ifndef TRASHCAN_H
#define TRASHCAN_H
#include <iostream>
#include <cstdlib>


using namespace std;


namespace cs52{
class TrashCan {
public:


  TrashCan( ); // object trashcan
  TrashCan( int size ); //object trashcan with specific size
  TrashCan( int size, int contents ); //object trashcan with specific size and content

  void setSize( int size ); //set the size of the transh
  void addItem( ); //add item to the trashcan
  void empty( ); //inform the user the trash can is empty
  void cover( ); //what to do when the lid is on
  void uncover( ); // what to do when the lid is off
  void dirty( ); //what to do when the trash can is dirty
  void notDirty( ); //what to do when the trash can is not dirty
  void removeItem( ); //remove item from the trash can
  void full( ); //what to do when the trash can is full




  void printCan( ); //display the trash can


  int getUsed( );//returns a value to varify which output error/contents
  
  friend ostream& operator <<(ostream& outs, TrashCan& can );//handles output of object trashCan
  friend istream& operator >>(istream& in, TrashCan& can);//takes the trashcan's content and size
  friend TrashCan operator +(const TrashCan& my_Size1, const TrashCan& my_Size2);
  friend TrashCan operator -(const TrashCan& my_Size1, const TrashCan& my_Size2);
  friend bool operator <(const TrashCan& my_Contents1,const TrashCan& my_Contents2);
  friend bool operator >(const TrashCan& my_Contents1, const TrashCan& my_Contents2);


  //pointers handling
  friend std::ostream& operator <<( std::ostream& outs, const TrashCan * drive );
  friend std::istream& operator >>( std::istream& ins, TrashCan * & drive );
private:
  bool myIsCovered; //a boolean value that determines if the lid is on or not
  bool my_Trash_Dirty;// a boolean value that determines if the trash can is dirty
  bool my_Trash; //a boolean value that determines if the trash can is full
  int my_Size; //a specific size of the trash can
  int my_Contents; //a specific content in the trash can


};


}
#endif