21. Нова реализация на свързани списъци

  Предефиниране на операции.
    Даване на ново значение на операция се нарича предефиниране (operator overloading). Операциите се предефинират за аргумети - обекти от даден клас, като типът на поне един от аргументите на бинарна операция трябва да е клас.
// overload.cpp
#include <iostream>
using namespace std;
#include "ccc_time.cpp"

/* Предефиниране на бинарна операция - с аргументи от клас Time и стойност от тип long */
long operator-(Time a, Time b)
/* ЦЕЛ: пресмята броя на секундите между два момента от време
   ПОЛУЧАВА: a, b - два момента от време
   ВРЪЩА: броя на секундите между a и b
*/
{  return a.seconds_from(b);   }

/* Предефиниране на бинарна операция + с аргументи от клас Time и тип long и стойност от
клас Time */
Time operator+(Time a, long sec)
/* ЦЕЛ: пресмята момент от време, отдалечен на зададен брой секунди
   ПОЛУЧАВА: a - момент от време
   ВРЪЩА: броя на секундите
*/
{  Time r = a;
   r.add_seconds(sec);
   return r;  }

/* Предефиниране на бинарна операция == с аргументи от клас Time и стойност от тип bool */

bool operator==(Time a, Time b)
/* ЦЕЛ: сравнява два момента от време
   ПОЛУЧАВА: a, b - два момента от време
   ВРЪЩА: true - ако те са равни
*/
{  return a.seconds_from(b) == 0;  }

/* Предефиниране на бинарна операция != с аргументи от клас Time и стойност от тип bool */

bool operator!=(Time a, Time b)
/* ЦЕЛ: сравнява два момента от време
   ПОЛУЧАВА: a, b - два момента от време
   ВРЪЩА: true - ако те не са равни
*/
{  return a.seconds_from(b) != 0;  }

/* Предефиниране на бинарна операция << с аргументи от клас ostream и клас Time и стойност
от тип ostream */
ostream &operator<<(ostream &out, const Time &a)
/* ЦЕЛ: отпечатва обект от тип Time
   ПОЛУЧАВА: out - изходен поток
             a - момент от време
   ВРЪЩА: out
*/
{  out << a.get_hours() << ":";
   if (a.get_minutes() < 10) out << "0";
   out << a.get_minutes() << ":";
   if (a.get_seconds() < 10) out << "0";
   out << a.get_seconds();
   return out;    }

/* Предефиниране на унарна операция - префиксна форма на ++ с аргумент от клас
Time и стойност от клас Time */
Time operator++(Time &a)
/* ЦЕЛ: добавя към момент от време 1 секунда
   ПОЛУЧАВА: a - момент от време
   ВРЪЩА: новият момент от време и променя a
*/
{ a = a + 1; return a; }

/* Предефиниране на унарна операция - постфиксна форма на ++ с аргумент от клас
Time и стойност от клас Time */
Time operator++(Time &a, int dummy)
/* ЦЕЛ: добавя към момент от време 1 минута
   ПОЛУЧАВА: a - момент от време
   ВРЪЩА: непромененият момент от време и променя a
*/
{ Time b = a;
  a = a + 60; return b;
}
 
int main()
{  Time now;
   cout << "Now it is " << now << "\n";
   Time later = now + 1000;
   cout << "A thousand seconds later it is " << later << "\n";
   Time now2;
   if (now == now2)
      cout << "It still is " << now2 << "\n";
   if (now != now2)
      cout << "It is already " << now2 << "\n";
   cout << "Another " << later - now2 << " seconds until "
        << later << "\n";
   now = Time();
   cout << "Now it is " << now << "\n";
   cout << "One second later " << (++now) << "\n";
   cout << "The same time " << (now++);
   cout << " and 60 seconds later " << now << "\n";
   return 0;
}
 

Now it is 11:42:51
A thousand seconds later it is 11:59:31
It still is 11:42:51
Another 1000 seconds until 11:59:31
Now it is 11:42:51
One second later 11:42:52
The same time 11:42:52 and 60 seconds later 11:43:52

Предефиниране на операции като член-функции на клас.
bool operator!=(Iterator a, Iterator b); /* външна за класа функция */
bool Iterator::operator!=(Iterator b);   /* член-функция */

string Iterator::operator*() const
{  assert(position != NULL);
   return position->data;  }

void Iterator::operator++(int dummy)
{  assert(position != NULL);
   position = position->next; }

void Iterator::operator--(int dummy)
{  if (position == NULL)  position = last;
   else                   position = position->previous;
   assert(position != NULL);   }

bool Iterator::operator!=(Iterator b) const
{  return position != b.position;   }

bool Iterator::operator==(Iterator b) const
{  return position == b.position;   }



  Шаблони.
    Класът  List (вж 20. Реализация на свързани списъци) съхранява свързан списък от низове, но ние искаме да може да съхранява стойности от произволен тип, както може стандартният клас list. За тази цел дефинираме шаблон на клас, като задаваме формален параметър T на шаблона с конструкцията
template<typename T> class List;
и фактически параметър на шаблона по познатата схема
List<string> staff;
    Ще пренапишем класовете, поддържащи свързан списък като използваме предефиниране на операции и шаблони.
// list3.cpp
#include <iostream>
#include <string>
#include <cassert>
using namespace std;

template<typename T>
class List;

template<typename T>
class Iterator;

template<typename T>
class Link  {
public:
   Link(T s);
private:
   T data;
   Link<T> *previous;
   Link<T> *next;
friend class List<T>;
friend class Iterator<T>;
};

template<typename T>
class List   {
public:
   List();
   void push_back(T);
   void insert(Iterator<T>, T);
   void erase(Iterator<T>);
   Iterator<T> begin();
   Iterator<T> end();
private:
   Link<T> *first;
   Link<T> *last;
};

template<typename T>
class Iterator   {
public:
   Iterator();
   T operator*() const;
   void operator++(int);
   void operator--(int);
   bool operator!=(Iterator<T>) const;
private:
   Link<T> *position;
   Link<T> *last;
friend class List<T>;
};

template<typename T>
Link<T>::Link(T s)
{ data = s;
  previous = NULL;
  next = NULL; }

template<typename T>
List<T>::List()
{ first = NULL; last = NULL; }

template<typename T>
void List<T>::push_back(T s)
{ Link<T> *newlink = new Link<T>(s);
  if (last == NULL)
  { first = newlink; last = newlink; }
  else
  { newlink->previous = last;
    last->next = newlink;
    last = newlink;
  }
}

template<typename T>
void List<T>::insert(Iterator<T> iter, T s)
{ if (iter.position == NULL)
  { push_back(s); return; }

  Link<T> *after = iter.position;
  Link<T> *before = after->previous;
  Link<T> *newlink = new Link<T>(s);
  newlink->previous = before;
  newlink->next = after;
  after->previous = newlink;
  if (before == NULL) first = newlink;
  else         before->next = newlink;
}

template<typename T>
void List<T>::erase(Iterator<T> iter)
{ assert(iter.position != NULL);
  Link<T> *remove = iter.position;
  Link<T> *before = remove->previous;
  Link<T> *after = remove->next;
  if (remove == first) first = after;
  else          before->next = after;
  if (remove == last) last = before;
  else     after->previous = before;
  iter.position = after;
  delete remove;
}

template<typename T>
Iterator<T> List<T>::begin()
{ Iterator<T> iter;
  iter.position = first;
  iter.last = last;
  return iter;
}

template<typename T>
Iterator<T> List<T>::end()
{ Iterator<T> iter;
  iter.position = NULL;
  iter.last = last;
  return iter;
}

template<typename T>
Iterator<T>::Iterator()
{ position = NULL; last = NULL; }

template<typename T>
T Iterator<T>::operator*() const
{ assert(position != NULL);
  return position->data;
}

template<typename T>
void Iterator<T>::operator++(int dummy)
{ assert(position != NULL);
  position = position->next;
}

template<typename T>
void Iterator<T>::operator--(int dummy)
{ if (position == NULL)  position = last;
  else                   position = position->previous;
  assert(position != NULL);
}

template<typename T>
bool Iterator<T>::operator!=(Iterator<T> b) const
{ return position != b.position; }

int main()
{ List<string> staff;
  staff.push_back("Cracker, Carl");
  staff.push_back("Hacker, Harry");
  staff.push_back("Lam, Larry");
  staff.push_back("Sandman, Susan");

/* добавя елемент на четвърто място */
  Iterator<string> pos;
  pos = staff.begin();
  pos++; pos++; pos++;
  staff.insert(pos, "Reindeer, Rudolf");

/* отстранява втория елемент */
  pos = staff.begin();
  pos++;
  staff.erase(pos);

/* отпечатва свързания списък */
  for (pos = staff.begin(); pos != staff.end(); pos++)
     cout << *pos << "\n";
   return 0;
}

Cracker, Carl
Lam, Larry
Reindeer, Rudolf
Sandman, Susan