Computer Science II -- Week 4

Introduction

Note that the links from this page are to handouts that will be distributed the night of class.  Only print out those handouts if you could not attend class.

Main topics this week:

Function Overloading
Operator Overloading
Difference between struct and class
Tips for writing classes
Stacks
In-class exercise

Function Overloading

What is function overloading?

Class constructors are one example, but any function (whether in a class or not) can be overloaded.

swap (int &, int &);
swap (string &, string &);
swap (float &, float &);

Operator Overloading

What is operator overloading?  (Not the same as function overloading)

Should do what makes sense for the class.

The compiler takes code like this:

Foo A, B;

A = B;

And actually generates code like this:

Foo A, B;

A.operator= (B);

Example: operator=

class Foo
{
public:
    Foo &operator= (const Foo &);

private:
    int x;
};

Foo &Foo::operator= (const Foo &rhs)
{
    if (this != &rhs)
    {
        x = rhs.x;
    }

    return *this;
}

What is the this pointer?

What is the significance of how we use it in operator=?

If you do not provide an operator=, the compiler provides one for you that simple copies values from data member to data member.  Remember the possible problems with the compiler provided copy constructor?  All the same problems exist with the compiler provided operator=.  When do you need to provide an operator=?

In general, anytime you use an operator with a class, the compiler generates a function call to the appropriate overloaded operator function.

Foo A, B;

A = B;

becomes:

Foo A, B;

A.operator= (B);

What would the compiler generate for:

Foo A, B, C;

C = A = B;

What would you expect to be generated for:

Foo A;

cout << A;

There is a second way to overload operators.  With operator= we used a member function of the class, and this is appropriate anytime the left side of the operator is an instance of the class.  When the left side of the operator is not an instance of the class, you use a non-member function.

The cout example becomes:

Foo A;

operator<< (cout, A);

The Foo class would be:

class Foo
{
private:
    int x;
};

ostream &operator<< (ostream &out, const Foo &rhs)
{
    out << rhs.x;
}

What's the problem with this example? 

Friend functions solve the problem.

class Foo
{
public:
    friend ostream &operator<< (ostream &, const Foo &);

private:
    int x;
};

ostream &operator<< (ostream &out, const Foo &rhs)
{
    out << rhs.x;
}

Use class member functions for overloading operators if the left hand side of the operators is an instance of the class.  Use non-member friend functions for overloading operators only if the left hand side of the operator is not an instance of the class.

Here's a handout that lists the most commonly overloaded operators and how you would declare them in a class.

Difference between struct and class

What is the difference between a struct and a class?

Tips for writing classes

In CS II you will have to write your own classes.  This handout has some tips on good class design. 

Stacks

Stacks are a data structure which holds many items, but you can only access the topmost item.  Stacks are a last-in first-out data structure.

Stack operations:

void push (data)

void pop ()

data top ()

Go through several operations and show what the stack looks like after each operation.

push (1)

push (2)

push (3)

top ()

pop ()

top ()

push (4)

pop ()

pop ()

push (5)

How would we implement a stack?  What C++ data structure could we use to hold the data contained in the stack?

What happens if the stack fill up?  Should it be able to fill up? 

Once we've decided what data structure to use in implementing the stack, the next thing we do is convert the stack operations in a .h file.  So the stack.h file would look like:

#ifndef STACK_H
#define STACK_H

class Stack
{
public:
    Stack ();
    ~Stack ();

    void push (int);
    void pop ();
    int top ();
};

#endif

Note that no magic has happened...we've simply taken the stack operations and added C++ stuff to make a class.  Given any set of operations, you should be able to do this easily.  If you're having trouble with this step, practice it.  You will be asked to do this often during the trimester.

Now, we need to consider each method in the stack class and decide what we need to do for that method.  We need to write an algorithm for each method.  Another way of thinking of this is that we're writing a description for what the method will do.

Once we know what the method will do, we need to decide what data we need to implement each method.  Here's a guideline for what data should go into the class itself as private data, versus what data should be local to a method:

If the data is only needed in one method, it should be local data to the method.  If the data is needed in more than one method, it should be private data in the class.

Go through the three basic operations and talk about what generally has to happen with each.

In-class exercise

Write the complete stack class methods.