Lecture 21 - Oct 24, 2023

Summary

In this lecture, we discuss copy constructor and operator= of linked lists. We also review the material for the midterm.

Today

Copy constructor, operator=, and midterm revision.

Recap on copy constructor

Creates an object from an existing one.

The default copy constructor does a shallow copy.

We need to do a deep copy:

  • Copy one node at a time.
  • p to iterate original list, np to build new list.
List::List(const List& original) {
  Node *p = original.head;
  Node *np = NULL;
  head = NULL;

  while (p != NULL) {
    Node *n = new Node(p->getData(), NULL);

    if (np == NULL) {
      head = n;
    } else {
      np->setNext(n);
    }

    p = p->getNext();
    np = n;
  }
}

Recap on operator equals

The idea is similar to the copy constructor, except that the lhs may not be empty. We must empty lhs first.

List& List::operator=(const List& original) {
  if (&original == this) {
    return *this;
  }

  if (head != NULL) {
    delete head;
    head = NULL;
  }

  // same as copy constructor body ----
  Node *p = original.head;
  Node *np = NULL;
  
  while(p != NULL) {
    Node *n = new Node(p->getData(), NULL);

    if (np == NULL) {
      head = n;
    } else {
      np->setNext(n);
    }

    p = p->getNext();
    np = n;
  }
  // ----

  return *this;
}

Recap on destructor

List::~List() {
  delete head;
}

Past exam questions

Fall 2019 - Q14

The following class is used to create objects that represent ordinary fractions n/d, consisting of a numerator n and a denominator d.

#include <iostream>

using namespace std;

class Fraction {
  private:
    int numerator;
    int denominator;

  public:
    Fraction(int num, int denm);
    int getNumerator();
    int getDenominator();
    void setNumerator(int num);
    void setDenominator(int denm);
    void print();
};

Fraction::Fraction(int num, int denm) {
  numerator = num;

  // should check that denm is not 0, but ignore for now
  denominator = denm;
}

int Fraction::getNumerator() {
  return numerator;
}

int Fraction::getDenominator() {
  return denominator;
}

void Fraction::setNumerator(int num) {
  numerator = num;
}

void Fraction::setDenominator(int denm) {
  // should check that denm is not 0, but ignore for now
  denominator = denm;
}

void Fraction::print() {
  cout << numerator << "/" << denominator << endl;
}

Define the operator overloads for the operation:

Fraction X(1,5);
Fraction Y(4,6);
...

___ = X * Y; // the first multiply operation
___ = X * 2; // the second multiply operation

The first operator is:

Fraction::Fraction operator*(Fraction& rhs) {
  Fraction w(numerator * rhs.numerator, denominator * rhs.denominator);
  return w;
}

The second operator is:

Fraction::Fraction operator*(int x) {
  Fraction w(x * rhs.numerator, denominator);
  return w;
}

Fall 2018 - Q7

The following is the definition/implementation of a class called Foo.

class Foo {
  private:
    int priv;

  public:
    Foo(int pv) { priv = pv; }
    
    Foo(const Foo src) { priv = src.priv; }
    
    Foo& operator=(Foo& rhs) {
      priv = src.priv;
      return this;
    }

    int getPriv() { return priv; }

    void setPriv(int pv) { priv = pv; }
};

Compiling the above definition/implementation results in one or more errors. Re-write the class so it is error-free. Write your answer (the entire definition/implementation).

The code requires the following corrections:

// Foo(const Foo src) { priv = src.priv; }
Foo(const Foo& src) { priv = src.priv; }
    
Foo& operator=(Foo& rhs) {
  priv = src.priv;
  // return this;
  return *this;
}

I cannot return a local variable by reference.

Fall 2021 Final - Q7

It is desired to implement an efficient deletion function in a linked list. You are given a linked list pointed to by head and a pointer node to a node in a linked list, which is guaranteed not to be the last node in the list (i.e., not the tail node). Write a function removeNode that removed this node from the list. You should not iterathe the nodes in the list.

You may assume the following is the definition of the class, ListNode. The head node of the linked list is pointed to by head.

class ListNode {
  public:
    int key;
    ListNode *next;
};

ListNode* head;

You are not allowed to change the function’s argument or return type.

void removeNode(ListNode *node) {
  ...
}

The solution is to copy the data from the next node into the current node, and then delete the next node.

void removeNode(ListNode *node) {
  ListNode *n = node->next;
  node->key = n->key;
  node->next = n->next;
  delete n;
}