Lecture 20: ADT Case study

Mar 25, 2024  β”‚  Last updated Apr 4, 2024 by Charlotte Curtis

HTML Slides html β”‚ PDF Slides PDF

Where we left off

  • const correctness with classes
  • Constructors and destructors
  • Function and operator overloading

Textbook Sections 10.2, 11.2

class Time {
public:
    Time(int h, int m, int s);
    Time();

    void write(std::ostream &out) const;
    void increment();
    bool operator<(const Time &t) const;
private:
    int hours;
    int minutes;
    int seconds;

    int compare(const Time &t) const;
};

Today’s topics

Textbook Sections 11.2, 13.2

Rules of operator overloading

Conventions of operator overloading

In general, the purpose of operator overloading is to make code more readable

Overloading thus far

Member vs non-member overloading

Overloading stream operators

Possible solution: friend functions

Note: this is somewhat contentious, as friends kind of break encapsulation. Can you think of a way to implement this without friend?

Overloading stream operators

emoji Operator overloading check-in 1/2

The primary purpose of operator overloading is to:

  1. Improve memory efficiency
  2. Improve performance
  3. Improve readability
  4. Make classes easier to write
  5. Encapsulation

emoji Operator overloading check-in 2/2

The << operator can’t be overloaded as a member function because:

  1. The left-hand side is a std::ostream
  2. It’s a binary operator
  3. It needs to be a const function
  4. It needs to be public
  5. It wants to have a friend

A common ADT: Stacks

Stacks

Specifying the ADT

Sample interface

class StringStack {
public:
    StringStack(int capacity);
    ~StringStack();

    bool empty() const;
    bool full() const;
    void push(const std::string &s);
    std::string pop();
    std::string peek() const;
private:
    ???
};

Sample usage

Let’s implement browser history using our stack ADT:

StringStack history(10); // max 10 pages
history.push("https://www.mymru.ca/");
history.push("https://stackoverflow.com/");
history.push("https://www.funnycatvideos.com/");

// go back to the previous page
load_url(history.pop());

// hover over the back button
if (history.empty())
    show_message("First page, can't go back\n");
else:
    show_message("Click to go back to: " + history.peek());

StringStack implementation V1

Complete private section for V1

class StringStack {
public:
...
private:
    int capacity;
    std::string *stack; // pointer to the array
    int top; // index of the top element
}

StringStack implementation V2

Complete private section for V2

class StringStack {
public:
...
private:
    struct Node {
        std::string data;
        Node *next;
    };
    Node *head; // pointer to the head node
    int capacity;
    int size; // number of elements in the stack
}

Constructors/destructors

Note: using namespace std; shouldn’t go in the header file, but it’s okay in .cpp

// Array version (V1)
StringStack::StringStack(int capacity) {
    string *stack = new string[capacity];
    this->capacity = capacity;
    top = -1;
}

StringStack::~StringStack() {
    delete[] stack;
}
// Linked list version (V2)
StringStack::StringStack(int capacity) {
    head = NULL;
    this->capacity = capacity;
    size = 0;
}

StringStack::~StringStack() {
    Node *curr = head;
    while (curr) {
        Node *next = curr->next;
        delete curr;
        curr = next;
    }
}

empty, full, and peek

// Array version (V1)
bool StringStack::empty() const {
    return top == -1;
}

bool StringStack::full() const {
    return top == capacity - 1;
}

std::string StringStack::peek() const {
    if (empty())
        return "";
    return stack[top];
}
// Linked list version (V2)
bool StringStack::empty() const {
    return size == 0;
}

bool StringStack::full() const {
    return size == capacity;
}

std::string StringStack::peek() const {
    if (empty())
        return "";
    return head->data;
}

push and pop

// Array version (V1)
void StringStack::push(const std::string &s) {
    if (full())
        return;
    stack[++top] = s;
}

std::string StringStack::pop() {
    if (empty())
        return "";
    return stack[top--];
}
// Linked list version (V2)
void StringStack::push(const std::string &s) {
    if (full())
        return;
    Node *new_node = new Node;
    new_node->data = s;
    new_node->next = head;
    head = new_node;
    size++;
}

std::string StringStack::pop() {
    if (empty())
        return "";
    std::string data = head->data;
    Node *next = head->next;
    delete head;
    head = next;
    size--;
    return data;
}

Summary

Coming up Next

Textbook Chapter 14



Previous: Lecture 19: More Classes
Next: Lecture 21: Recursion