static data members

Typical use:
keeping a count of the instantiated
objects of a particular class


static data members

1. declaration

class Obj {
  public:
    static int count;
    Obj();
    ~Obj();
};

2. initialization is outside the
declaration, but typically inside
the header file

int Obj::count = 0;

The scoping operator is required.

count exists, even if no objects
of type Obj are instantiated.

static data members

3. constructor and destructor

  Obj::Obj() {
    count++;
  }


  Obj::~Obj() {
    count--;
  }

Operator Overloading


The Goal of Operator Overloading

Instead of code similar to:

   // for each element of an array, apply
   // the same operation
   for (i = 0; i < LENGTH; i++) {
      c[i] = a[i] + b[i];
   }

If a, b, and c are objects of an array class,
we can define the + operator on the array class,
resulting in code such as

   c = a + b;

The overloaded operator is a function
(called an operator function)

Overloaded operator prototype:

   returntype operatorop(  );
where op is replaced by the operator's symbol.

IntList example prototype for
the overloaded assignment operator:

   Intlist & operator=(const IntList & L);

In the array objects example,

for

   c = a + b;

the compiler substitutes the function call
   c = a.operator+(b); 

We get a member function (operator+) call
for the overloaded operator.


The Overloaded Assignment Operator

It is often needed in a program,
to accomplish:


The Default Copy Assignment Operator

Like the defaults for a constructor, a destructor, and a copy constructor, a C++ class is given a default copy assignment operator, if one is not defined.

This default does a shallow copy of all data members.


The default copy assignment operator

  1. Does nothing if called with
        ob1 = ob1;
    
  2. Copies each data member of RHS object into LHS object.

Note that the LHS object and RHS object are existing instances of objects. So, nothing is constructed for the default copy assignment operator invocation:

    ob2 = ob1;










But, we may need more than the default, in the same cases that we need to define a copy constructor (because a shallow copy is not enough) and a destructor.

Consider the assignment

    ob2 = ob1;

The initial state, before assignment:








This operator= function must

  1. do nothing if an object is assigned to itself
      ob1 = ob1;
    
  2. not leak ob2 memory
  3. make a deep copy of ob1







the IntList overloaded = operator

// Overload the assignment operator
IntList & IntList::operator=(const IntList &L) {
  cout << "assignment" << endl;
  // check for self-assignment - if so, do nothing
  if (this == &L)
  return *this;

  else {
    delete [] items;     // free storage pointed to by items
    items = new int[L.arraySize];  // allocate new array
    arraySize = L.arraySize;       // set arraySize

    // copy items from L's array to the new array
    // (and also set numItems)
    for (numItems = 0; numItems < L.numItems; numItems++)
    items[numItems] = L.items[numItems];
  }

  return *this;
}


Copyright © Karen Miller, 2007, 2008, 2009