2. Objects and Classes

Objective: We'll show

Reference: Weiss, Chapter Two.

2.1 Basic class Syntax

#ifndef _IntCell_H_
#define _IntCell_H_

// A class for simulating an integer memory cell.
//
// File: IntCell.h
//
class IntCell
{
public:
   // Constructor.  Initial value is initialValue.
   explicit IntCell(int initialValue = 0)
     : storedValue(initialValue) {}

   // Copy constructor.
   IntCell(const IntCell& rhs)
     : storedValue(rhs.storedValue) {}

   // Destructor.
   ~IntCell() {}

   const IntCell& operator=(const IntCell& rhs);

   // Accessor (or inspector) method.
   int read() const { return storedValue; }

   // Mutator method.
   void write(int x) { storedValue = x; }

private:
   int storedValue;
};
#endif

//
// File: IntCell.cpp
//

const IntCell& IntCell::operator=(const IntCell& rhs)
{
   if (this != &rhs)  // standard alias test
   {
      storedValue = rhs.storedValue;
   }
   return *this;
}

2.2 An IntCell Test Program

#include "intCell.h"

int main()
{
  IntCell m;  // or, IntCell m(0); but not IntCell m();
  m.write(5);
  cout << "Cell contents: " << m.read() << endl;
  return 0;
}

2.3 Defaults may not work

class IntCell
{
public:
  explicit IntCell(int initialValue = 0)
    { storedValue = new int(initialValue); }

  int read() const
    { return *storedValue; }

  void write(int x)
    { *storedValue = x; }

private:
  int *storedValue;
};

int f()
{
   IntCell a(2);
   IntCell b = a;
   IntCell c;

   c = b;
   a.write(4);
   cout << a.read() << endl << b.read()
        << endl << c.read << endl;

   return 0;
}

2.4 Rational Number Test Program

#include "Rational.h"
#include <iostream>
using namespace std;

int main()
{
   Rational x;
   Rational sum = 0;
   Rational max = 0;
   int n = 0;

   cout << "Type as many rationals as you want" << endl;
   while (cin >> x)
   {
      cout << "Read " << x << endl;
      sum += x;
      if (x > max)
      {
         max = x;
      }
      n++;
   }
   cout << "Read " << n << rationals << endl;
   if (max > IntType(0))
   {
      cout << "Largest number is " << max << endl;
   }
   if (n > 0)
   {
      cout << "Average is " << sum/IntType(n) << endl;
   }
   return 0;
}

2.5 The Rational Class Interface

//
// File: Rational.h
//
#include <iostream>
using namespace std;

typedef long IntType;

class Rational
{
public:
   Rational(const IntType& numerator = 0)
     : numer(numerator), denom(1) {}

   Rational(const IntType& numerator, const IntType& denominator)
     : numer(numerator), denom(denominator)
     { fixSigns(); reduce(); }

   Rational(const Rational& rhs) : numer(rhs.numer), denom(rhs.denom) {}

   ~Rational() {}

   const Rational& operator= (const Rational& rhs);
   const Rational& operator+=(const Rational& rhs);
   const Rational& operator-=(const Rational& rhs);
   const Rational& operator*=(const Rational& rhs);
   const Rational& operator/=(const Rational& rhs);

   Rational operator+(const Rational& rhs) const;
   Rational operator-(const Rational& rhs) const;
   Rational operator*(const Rational& rhs) const;
   Rational operator/(const Rational& rhs) const;

   bool operator< (const Rational& rhs) const;
   bool operator<=(const Rational& rhs) const;
   bool operator> (const Rational& rhs) const;
   bool operator>=(const Rational& rhs) const;
   bool operator==(const Rational& rhs) const;
   bool operator!=(const Rational& rhs) const;

   const Rational& operator++();      // prefix
   Rational operator++(int);          // postfix
   const Rational& operator--();      // prefix
   Rational operator--(int);          // postfix
   const Rational& operator+() const; // unary +
   Rational operator-() const;        // unary -
   bool operator!() const;

   double toDouble() const
     { return static_cast< double >(numer) / denom; }

   friend ostream& operator<<(ostream& out, const Rational& value);

   friend istream& operator>>(ostream& in, Rational& value);

private:
   IntType numer;
   IntType denom;

   void fixSigns();  // ensure denom >= 0
   void reduce();    // ensure lowest form
};

2.6 Initialization and Type Conversion

2.7 The Private Member Functions

void Rational::fixSigns()
{
   if (denom < 0)
   {
      denom *= -1;
      numer *= -1;
   }
}

void Rational::reduce()
{
   IntType d = 1;

   if (denom != 0 && numer != 0)
   {
      if ((d = gcd(numer, denom)) > 1)
      {
         numer /= d;
         denom /= d;
      }
   }
}

2.8 Assignment Operators

const Rational& Rational::operator=(const Rational& rhs)
{
   if (this != &rhs)
   {
      numer = rhs.numer;
      denom = rhs.denom;
   }
   return *this;
}

const Rational& Rational::operator+=(const Rational& rhs)
{
   numer = numer * rhs.denom + rhs.numer * denom;
   denom = denom * rhs.denom;
   reduce();
   return *this;
}

2.9 Some Other Operators

Rational Rational::operator+(const Rational& rhs) const
{
   Rational answer(*this);
   answer += rhs;
   return answer;
}

bool Rational::operator==(const Rational& rhs) const
{
   return numer * rhs.denom == denom * rhs.numer;
}

const Rational& Rational::operator++() // prefix
{
   numer += denom;
   return *this;
}

Rational Rational::operator++(int)  // postfix
{
   Rational tmp = *this;
   numer += denom;
   return tmp;
}

bool Rational::operator!() const
{
   return !numer;
}

const Rational& Rational::operator+() const
{
   return *this;
}

Rational Rational::operator-() const
{
   return Rational(-numer, denom);
}

2.10 I/O Friends

istream& operator>>(istream& in, Rational& value)
{
   in >> value.numer;
   value.denom = 1;

   char ch;
   in.get(ch);
   if (!in.eof())
   {
      if (ch == '/')
      {
         in >> value.denom;
         value.fixSigns();
         value.reduce();
      }
      else
      {
         in.putback(ch);  // unread ch
      }
   }
   return in;
}

ostream& operator<<(ostream& out, const Rational& value)
{
   if (value.denom != 0)
   {
      out << value.numer;
      if (value.denom != 1)
         out << '/' << value.denom;
      return out;
   }

   // messy code for denom == 0
   if (value.numer == 0)
   {
      out << "Indeterminate";
   }
   else
   {
      if (value.numer < 0)
      {
         out << '-';
      }
      out << "Infinity";
   }
   return out;
}

2.11 Operator Overloading

2.12 Some Common Idioms

2.13 The string Class (mystring.h)

#ifndef _MY_STRING_H_
#define _MY_STRING_H_

#include <iostream>
using namespace std;

class string
{
public:
   string(char ch);
   string(const char *cstring = "");
   string(const string& str);
   ~string() { delete [] buffer; }

   const string& operator= (const string& rhs);
   const string& operator+=(const string& rhs);

   const char *c_str() const { return buffer; }
   int length() const {return strLength; }

   char  operator[](int k) const;  // accessor
   char& operator[](int k);        // mutator

private:
   int strLength;    // length of string
   int bufferLength; // capacity of buffer
   char *buffer;     // storage for characters
};



ostream& operator<<(ostream& out, const string& str);
istream& operator>>(istream& in, string& str);
istream& getline(istream& in, string& str,
                 char delim = '\n');

bool operator==(const string& lhs, const string& rhs);
bool operator!=(const string& lhs, const string& rhs);
bool operator< (const string& lhs, const string& rhs);
bool operator<=(const string& lhs, const string& rhs);
bool operator> (const string& lhs, const string& rhs);
bool operator>=(const string& lhs, const string& rhs);

#endif

2.14 The string Class (Constructors)

#include <cstring>
#include "mystring.h"

string::string(const char *cstring)
{
   if (cstring == NULL)
   {
      cstring = "";
   }
   strlength = strlen(cstring);
   bufferLength = strLength + 1;
   buffer = new char[bufferLength];
   strcpy(buffer, cstring);
}

string::string(char ch)
{
   strLength = 1;
   bufferLength = 2;
   buffer = new char[2];
   buffer[0] = ch;
   buffer[1] = '\0';
}

string::string(const string &str)
{
   strLength = str.length();
   bufferLength = strLength + 1;
   buffer = new char[bufferLength];
   strcpy(buffer, str.buffer);
}

2.15 The string Class (Assignments)

const string& string::operator=(const string& rhs)
{
   if (this != &rhs)
   {
      if (bufferLength < rhs.length() + 1)
      {
         delete [] buffer;
         bufferLength = rhs.length() + 1;
         buffer = new char[bufferLength + 1];
      }
      strLength = rhs.length();
      strcpy(buffer, rhs.buffer);
   }
   return *this;
}

const string& string::operator+=(const string& rhs)
{
   if (this == &rhs)  // alias test; important!
   {
      string copy(rhs);
      return *this += copy;
   }

   int newLength = length() + rhs.length();

   if (newLength >= bufferLength)
   {
      bufferLength = 2 * (newLength + 1);
      char *oldBuffer = buffer;
      buffer = new char[bufferLength];
      strcpy(buffer, oldBuffer);
      delete [] oldBuffer;
   }

   strcpy(buffer + length(), rhs.buffer);
   strLength = newLength;
   return *this;
}

2.16 The string Class (Indexing)

char& string::operator[](int k)
{
   if (k < 0 || k >= strLength)
   {
      throw StringIndexOutOfBoundException();
   }
   return buffer[k];
}

char string::operator[](int k) const
{
   if (k < 0 || k >= strLength)
   {
      throw StringIndexOutOfBoundException();
   }
   return buffer[k];
}

2.17 The string Class (I/O)

ostream& operator<<(ostream& out, const string& str)
{
   return out << str.c_str();
}

istream& operator>>(istream& in, string& str)
{
   char ch;
   str = "";
   if (in >> ch)
   {
      do
      {
         str += ch;
         in.get(ch);
      } while(!in.fail() && !isspace(ch));

      if (isspace(ch))
      {
         in.putback(ch);
      }
   }
   return in;
}

istream& getline(istream& in, string& str, char delim)
{
  char ch;
  str = "";
  while (in.get(ch) && ch != delim)
    str += ch;
  return in;
}

2.18 The string Comparisons

bool operator==(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) == 0;
}

bool operator!=(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) != 0;
}

bool operator<(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) < 0;
}

bool operator<=(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) <= 0;
}

bool operator>(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) > 0;
}

bool operator>=(const string& lhs, const string& rhs)
{
   return strcmp(lhs.c_str(), rhs.c_str()) >= 0;
}