overloading cout for a template linked list

Good morning everyone!

I need a little assistance in overloading cout for my linked list. The truth is, I have no idea how to do it. I tried searching everywhere but no where explains it to the depth that I need it.

This is an assignment (I've already written the whole program but I can't output anything without overloading cout). Also, I have more than one object to output, and the iteration required... I'm at a loss.

My lecturer said "Write an assignment operator and a friend function to output the linked list"

I've got 3 source files. A ListNode.h, list.h and main.cpp... In my list.h file, I put:

1
2
template <typename OUTPUT >
  friend ostream &operator <<(ostream &, const List<NODETYPE> & );


before this, I had <typename NODETYPE> but I get an error about shadows param, which is probably because it's in my template class.

My questions are:

Where exactly do I put this code? I have it before my public and private functions in my class before all my function prototypes. Is this the right location for it?

Also, how do I define it: In my main.cpp (that I'm not allowed to alter in any way as this is what the lecturer provided for us) I have these objects (though they may differ..he just provided examples so we could test if the functions all do what they're supposed to):

1
2
List<int> Li, Li2, Li3;
  List<double> Ld, Ld2;


and I also have several cout statements like:

cout << "Ld is: " << Ld << endl;

I've tried defining the overload statement like this but it doesn't work:

1
2
3
4
5
6
template<typename NODETYPE>
ostream &operator <<(ostream &output, const List<NODETYPE>& list)
{
    output << list;
    return output;
}


Any help is greatly appreciated!! Thanks =]

Last edited on
The "shadows a parameter" error occurs when you try to use the same identifier as a class variable and as an argument name (or parameter) to a function. I don't know how your list is defined, but you should be careful to have unique names for everything -- at least until you understand where you can reuse them for clarity.

BTW, on terminology, you are not "overloading cout", but you are overloading the stream insertion operator for your type.

The whole point is that the computer does not know how to cout << my_type_of_thing, so you have to teach it. In your example above, you are trying to teach it by doing it. That is kind of like telling someone that the way to activate the flumoxiter is to activate the flumoxiter. You need to be specific: "Press the red button on the left and pull the lever to activate the flumoxiter."


One way to help with this kind of assignment is to remember that a function (in this case, the insertion operator) is a shortcut to do something you would have to write yourself. To print your list, what do you do? It might be something like:

1
2
3
4
5
6
List <int> ::node_type* node = Li.head;
while (node != NULL)
{
    cout << node->value;
    node = node->next;
}

(I don't know how your list is actually implemented, but I presume that there is some kind of node type and a node_type* head; in the List<> object.)

We can use this information to write the insertion operator. All we really have to do is wrap it up in the function and change "cout" to "output":

1
2
3
4
5
6
7
8
9
10
11
template <typename NodeType>
ostream &operator <<(ostream &output, const List<NodeType>& list)
{
    List <NodeType> ::node_type* node = list.head;
    while (node != NULL)
    {
        output << node->value;
        node = node->next;
    }
    return output;
}

Hope this helps.
You're the first person that has really explained overloading clearly. Everyone else makes it seem so confusing, and you just made me feel silly for not getting it earlier haha.

Well, I somewhat get it now, but when trying to implement it, I received errors about my private data members.. I thought that making it a friend would allow me to access private data members as well. I'm not sure if I did something wrong.

For every instance that I used a private data member in my execution, it has given me an error. (firstPtr, data, nextPtr)

1
2
 template <typename OUTPUT >
  friend ostream &operator <<(ostream &, const List<NODETYPE> & );


1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename NODETYPE>
ostream &operator <<(ostream &output, const List<NODETYPE>& list)
{
    ListNode<NODETYPE> *currentPtr = list.firstPtr;

    while(currentPtr != 0)
    {
        output << currentPtr->data;
        currentPtr = currentPtr->nextPtr;
    }

      return output;
}


These are my pointers and functions that work within my linked list to make it work the way it does... I'm not sure what to do... I'll try something, but I doubt it'll make a difference..
Last edited on
So the ListNode<> and List<> types are distinct classes? If they are, you must make them friends, as well as the insertion operator. To do that, you will have to prototype (or "forward declare") one first.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// We need to forward declare List<> so that it can be a friend of ListNode<>
template<typename NodeType>
class List;

// I am the ListNode<>
template<typename NodeType>
class ListNode
{
    NodeType data;
    ListNode* nextPtr;

    // These are ListNode<>'s friends: they can access my private members
    template<typename T> friend class List;
    template<typename T> friend ostream &operator <<(ostream &, const List<T> & );
};

// I am the List<> type. Since I am a friend of ListNode<>, I
// can play with all of ListNode<>'s members.
template<typename NodeType>
class List
{
    ListNode<NodeType> *firstPtr;

    // The insertion operator function also needs to access my private stuff.
    template<typename T> friend ostream &operator <<(ostream &, const List<T> & );

public:
      ...
};

// I am the insertion operator. I can access all of both List<>'s and ListNode<>'s members.
template<typename NodeType>
ostream &operator <<(ostream &output, const List<NodeType> &list)
{
    ...
}

Notice that we need to declare the insertion operator as a friend of both classes, since we want to use them both in the operator function.


The other trick is to declare the ListNode<> as a class internal to the List<> class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename NodeType>
class List
{
    struct ListNode
    {
        NodeType data;
        ListNode *nextPtr;
    };

    ListNode* firstPtr;

    // Same as ever: the << operator needs to be able to access my internal stuff
    template<typename T> friend ostream &operator <<(ostream &, const List<T> & );

public:
    ...
};


One other thing. You are using ALL CAPS for template arguments, but that is not the way people normally do it. Typically CamelCase is used. Of course, it works fine either way, but it will confuse people who are accustomed to seeing ALL CAPS as preprocessor macros.

Hope this helps.
Topic archived. No new replies allowed.