简体   繁体   中英

Overloading operator<< for user defined MyList

I cannot use std::list . The goal is to create a user defined MyList that can handle any data type. My problem is with my nested iterator class and possibly my function for overloading operator<<. I have been at this for awhile and I am stuck. Since the deadline is pretty close, I figure that I should risk my neck and ask the question here. It will be great if someone can assist me with this.

I realized that there are memory leaks in my code, but thats not my main concern at the moment. I also realized that having so many friend function is not a good programming practice, I am planning to use getData() and setData() function to get/set the private variable within node later.

So please overlook the above 2 problems...

Error message:

"MyList.h", line 67: Error: iterator is not defined.

I'll include the whole header file just so that in case people need to see it. I'll include a comment at line 67 where the error is. Then I'll also include a section of my main function that uses the iterator to show how I am trying to set the iterator and iterate through the list.

#include<iostream>
#include<cstddef>

template<class T>
class Node
{
   friend void MyList<T>::push_front(T aData);
   friend void MyList<T>::push_back(T aData);
   friend void MyList<T>::pop_front();
   friend T MyList<T>::front();
   friend void MyList<T>::print();
   friend MyList<T>::~MyList();
   friend std::ostream& operator<<(std::ostream&, Node<T>&);
   private:
      T data;
      Node *next;
      Node *prev;
   public:
      Node(T aData);

};

template<class T>
class MyList
{
   Node<T> *head;
   Node<T> *tail;
   public:
      MyList();
      ~MyList();
      void push_front(T aData);
      void push_back(T aData);
      T front();
      void pop_front();
      void operator=(MyList<T>& another_List);

      void print();  //Test function. Delete later.

      class iterator
      {
         private:
            MyList& object;
            Node<T> *current;
         public:
            iterator(MyList<T>&, Node<T>*);     // iterator a(*this, head);
                                                // MyList<int>::iterator a = list.Begin();
            iterator operator++();          // a++
            iterator operator++(int);           // ++a
            iterator operator--();
            bool operator!=(iterator);
            friend std::ostream& operator<<(std::ostream&, iterator&);
      };

      iterator Begin();
      iterator End();
};

template<class T>
std::ostream& operator<<(std::ostream& out, Node<T>& n)
{
   out << *n.current << ' ';

   return out;
}

template<class T>
std::ostream& operator<<(std::ostream& out, iterator& i)  //ERROR
{
   out << i->current << ' ';

   return out;
}

template<class T>
Node<T>::Node(T aData)
{
   data = aData;
}

template<class T>
MyList<T>::MyList()
{
   head = NULL;
}

template<class T>
MyList<T>::~MyList()
{
   Node<T> *temp;

   while(head != NULL)
   {
      temp = head;
      head = head->next;
      delete temp;
   }
   head = NULL;
}

template<class T>
void MyList<T>::push_front(T aData)
{
   if(head == NULL)
   {
      head = new Node<T>(aData);
      head->next = tail;
      head->prev = NULL;
      tail->prev = head;
   }
   else
   {
      head->prev = new Node<T>(aData);
      head->prev->prev = NULL;
      head->prev->next = head;
      head = head->prev;
   }
}

template<class T>
void MyList<T>::push_back(T aData)
{
   if(head == NULL)
   {
      head = new Node<T>(aData);
      head->prev = NULL;
      head->next = tail;
      tail->prev = head;
   }
   else
   {
      tail->prev->next = new Node<T>(aData);
      tail->prev->next->prev = tail->prev;
      tail->prev->next->next = tail;
      tail->prev = tail->prev->next;
   }
}

template<class T>
T MyList<T>::front()
{
   return head->data;
}

template<class T>
void MyList<T>::pop_front()
{
   if(head == NULL)
      std::cout << "The List is empty!" << endl;
   else
   {
      head = head->next;
      head->prev = NULL;
   }
}

template<class T>
void MyList<T>::print()
{
   while(head != NULL)
   {
      std::cout << "Test print function" << std::endl;
      std::cout << '[' << head->data << ']' << std::endl;
      head = head->next;
   }
   std::cout << "End of test print function" << std::endl;
}

template<class T>
MyList<T>::iterator::iterator(MyList<T>& list, Node<T>* p)
{
   object = list;
   current = p;
}

template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator++()
{
   if(current == object.tail)
   {
   }
   else
      current = current->next;
   return this;
}

template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator++(int)
{
   if(current == object.tail)
   {
   }
   else
      current = current->next;
   return this->prev;
}

template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator--()
{
   if(current == object.head)
   {
   }
   else
      current = current->prev;
   return this;
}

template<class T>
bool MyList<T>::iterator::operator!=(iterator b)
{
   return (this.current == b.current);
}

template<class T>
typename MyList<T>::iterator MyList<T>::Begin()
{
   return iterator(object, head);
}

template<class T>
typename MyList<T>::iterator MyList<T>::End()
{
   return iterator(object, tail);
}

main.cpp

   MyList<int>::iterator i = aList.Begin();
   while(i != aList.End())
   {
      cout << i;
      i++;
   }

Since the definition of your iterator class is nested inside the definition of your MyList class template, for all code outside out MyList , its name is MyList<whatever>::iterator .

Perhaps you intended something slightly different in the code that contains the error though. While you've defined it as a template:

template<class T>
std::ostream& operator<<(std::ostream& out, iterator& i)  //ERROR
{
   out << i->current << ' ';

   return out;
}

You don't seem to be using its template parameter ( T ) at all. Perhaps you really intended something more like:

template<class iterator>
std::ostream& operator<<(std::ostream& out, iterator& i)  //ERROR
{
   out << i->current << ' ';

   return out;
}

In this case you don't need to supply a qualifier, since the iterator here is just referring to the template parameter. When you use this, the compiler will normally deduce the type of the iterator you actually pass.

Note that it's unnecessary but somewhat traditional to specify the iterator category in a template parameter like this, so you'd typically use something like OutIterator instead of just iterator for the template parameter.

This isn't really very generic though -- in particular, the ->current means it'll only really work for your specific iterator type. More typical code would overload operator * for the iterator type, so client code will just dereference the iterator. Also note that iterators are normally assumed to be "lightweight" enough that they're normally passed by value, not by reference.

class iterator {
    // ...
    T operator*() { return *current; }
};

// ...
template<class OutIt>
std::ostream& operator<<(std::ostream& out, OutIt i)
{
    out << *i << ' ';
    return out;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM