static data member


static member functions

For operating on private, static data members!

 class X {
   private:
     static int Z;  // static data member
 }
 int X::Z = 0;  // initialize

Add a public member function to operate on Z:

 class X {
   private:
     static int Z;  // static data member
   public:
     static void incrZ();
 }
 int X::Z = 0;  // initialize

And, outside the class, use this function:

 X::incrZ();


Remember, there is only 1 Z for all X objects. . .so, a static function is not invoked on a particular object.


static member function (private)

Not invoked on an object.
Therefore, no this pointer!
And, can only access static data members!

For use when the member function is only to be used within the class.

Example: We have a linked list Node structures. To implement a function that frees up the space taken by this linked list, use a private, static function:

  private:
    static void freeList(Node *L); // declaration

Use:

  List::~List() {    // destructor
    freeList(head);
  }

Both the destructor (shown here) and the overloaded assignment operator (not shown) would use this function. The overloaded assignment operator uses this function to properly do memory management on the LHS object.


operator overloading


The overloaded operator is implemented
with a function (an operator function)

Overloaded operator prototype:

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

(from Polynomial class)
Prototype for an overloaded assignment operator:

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

Using the overloaded assignment operator:

   p1 = p2;

For this statement, the compiler
substitutes the function call
   p1.operator=(p2);

The operator=() operator function within the Polynomial class is invoked, because p1 is a Polynomial class object.


With code such as

  ob2 = ob1;

this operator=() function must

  1. do nothing if an object is assigned to itself,
    for example (if the calling code had been):
      ob1 = ob1;
    
  2. not leak ob2 memory
  3. make a deep copy of ob1







Limitations:


Advice:

Use overloaded operator functions to
do something suggested by the operator!

If you saw this code:

  flag = (ob2 && ob1); 
the overloaded operator should do a logical and.

If it instead swapped two unequal objects,
and returned a boolean indicating that the swap occurred,
yuck!
The alternative? Define a function!

  boolean swap_if_not_equal(  );

A problem solved by making friends.

Suppose we want to do multiplication of a
matrix object by a double.

  A = B * 12.6;

Define operator*() for matrices,
and the compiler generates the call

  A = B.operator*(12.6);  // works well

But, reverse the order of the operands:

  A = 12.6 * B;

and the compiler cannot generate a call
to the member function operator*()

  A = 12.6.operator*(B);  // nasty!

One possible solution:

Define an operator*() function that handles
this particular case

  A = 12.6 * B;

The additional operator*() definition

  Matrix operator*(double x, Matrix m) {
    return (m * x);  
  }

Note: This is not a Matrix member function!


Member function (not static)
is invoked on an object. The call appears as

  obj.fcn(  )

Nonmember function
is not invoked on an object. The call appears as

  fcn(  )

Friends also solve the problem.

They can be

  1. a function which is a friend
  2. a class which is a friend

A friend describes access control to a class.

A friend has the same access priviledges
as a member function.
A friend can access private data members.


The friend function

It is a nonmember function.

Its declaration (prototype) goes in the class declaration!
Placed before the public or private keyword is fine.

The keyword friend is added.

 friend Matrix operator*(double x, Matrix & m);

Place the friend function definition with the other class definitions.

The definition does not use Matrix::, and

does not use the keyword friend.

 Matrix operator*(double x, Matrix & m) {
   // may access private data members of m
 }

Note:

Ask 10 different C++ programmers to
write a specific program in C++, and
you will likely get 6 dramatically different
programs.

What could be different?


Look at the Polynomial code example.

It was written by Hasti and Skrentny.

Karen would have produced a different
implemention.

However, it provides lots of excellent
discussion points!


overloading << for cout

Consider the following code:

  int x = 3;
  int y = 5;
  cout << "x=" << x << "  y=" << y << endl;

The output appears

   ------------------
  |x=3  y=5
  | 
  |^

cout is an ostream class object,
and the << operator is overloaded.


The << operator is evaluated left-to-right.

First step:

  (cout << "x=") << x . . .

This prints x=, and
returns a reference to cout

Second step is then

  (cout <<  x) << "  y=" . . .

This prints the value of x, and
returns a reference to cout


The Polynomial implementation
for the overloaded << operator:

Declaration of nonmember function:

ostream & operator<<(ostream & out, const Polynomial & p);

Definition:

ostream & operator<<(ostream & out, const Polynomial & p) { 
   p.print(out);  // calls member function
   return out;
}

An alternative Polynomial implementation
for the overloaded << operator.

Make it a friend function.

Declaration:

friend ostream & operator<<(ostream & out, const Polynomial & p);

Definition:

ostream & operator<<(ostream & os, const Polynomial & p) {
  if (size == 0)
    return os;

  for (int i=   . . .
    os << coefs[i] << "x^" <<   . . .
    
  return os;
}

friend function can access private data members

uses overloaded << on cout, giving it primitive types


Copyright © Karen Miller, 2007