i have done the <<operator overloading but it's not working

1.7k views Asked by At

i have overloaded the '<<' operator in the linked class implementation, and i declared the .cpp file in my main function, but it's not working, and this error occurs: undefined reference to operator<& list)

this is the declaration of the ostream function in linkedlist.h file:

  friend std::ostream& operator<< (std::ostream& os, LinkedList<T>& list);

and this is the implementation of the ostream function:

 template <typename T>
   std::ostream& operator<< (std::ostream& os, LinkedList<T> list) 
 {
  list.current = list.start;
  while(list.current != NULL)
    {
        os<< list.current->info<<" -> ";
        list.current = list.current->next;
    }
    os<<"NULL"<<endl;
    return os;
 }

In the main function, I have created a list that has object from SavingAccount class

LinkedList <SavingAccount> list;

and the error occurs in the main function in this line:

 cout << list <<endl;

well.. this is the LinkedList class implementation:

#include "LinkedList.h"
#include "SavingAccount.h"
#include <cstddef>
using namespace std;

template <typename T>
LinkedList<T>::LinkedList()
{
   start = NULL;
   current = NULL;
}
template <typename T>
LinkedList<T>::~LinkedList()
  {
    // Add code.
  }

  template <typename T>
   std::ostream& operator<< (std::ostream& os,const LinkedList<T>& list) {
    list.current = list.start;
    while(list.current != NULL)
    {
        os<< list.current->info<<" -> ";
        list.current = list.current->next;
    }
    os<<"NULL"<<endl;
    return os;
  }

and this is the header file of LinkedLins class:

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include<iostream>

using namespace std;


template <typename T>
struct Node{
    T info;
    Node<T> *next;
};

template <typename T>

class LinkedList
{
    Node<T> *start;
    Node<T> *current;
public:
    LinkedList();
    ~LinkedList();
    friend std::ostream& operator<< (std::ostream& os, const LinkedList<T>& list);

  };

#endif // LINKEDLIST_H

i hope you guys can help me with that, your help is much appreciated

3

There are 3 answers

1
lapk On BEST ANSWER

Ok, after you posted your code it seems your problem is that you split LinkedList template declaration and implementation between a header and a source file. Unless you are doing explicit instantiation in the source file, you cannot do this: you cannot separate template declaration and implementation, they have to be in one header.

You need to put the content of your LinkedList.cpp in LinkedList.h, get rid of the source file altogether, and just include the updated header where you need it.

P.S. Also, modifying an object through a const reference is not a good idea, generally speaking. Compiler will not like it. You might want to reconsider your design.

P.P.S. If you REALLY want and mean to modify some data members in objects of a class that you access via const reference, you will need to declare those data members as mutable.

P.P.P.S. To elaborate on template function foo friend declarations for a template bar class and avoid lengthy discussions in comments.

If you are defining such function together with its declaration inside the class, it is a straightforward thing - just use friend keyword. For example, friend void foo( bar< T > & ) { ... }.

If you defining it separately outside the class, you need to use slightly different syntax in the declaration and avoid shadowing of template parameters: template< typename U > friend void foo( bar< U > & ) { ... } (assuming U was not used in template parameters in bar class declaration). And then you define it outside the class.

If you want to specify default template arguments for the foo it gets even more trickier. You cannot use default template arguments in friend declaration, so you have to forward declare everything:

template< typename T > class bar;

template< typename T = int >
void foo( bar< T > & );

template< typename T >
class bar
{
  template< typename U >
  friend void foo( bar< U > & );
};

template< typename T >
void foo( bar< T > & )
{
 ...
}

And one last P.P.P.P.S (I hope!). Since you are using operator << for type SavingAccount in your operator << for LinkedList, you need to define operator << for SavingAccount too.

NOTE TO SELF : Don't answer questions in comments' section to another answer ;).

13
Oleksiy On

I'm not sure if this is what causing the error, but your function definition is different from your function declaration:

// you left out a & (reference sign) - LinkedList<T>& list in declaration
std::ostream& operator<< (std::ostream& os, LinkedList<T> list) 

EDIT

Petr Budnik is right, you need to keep your template implementation in the same file as your definition.

There is one thing he didn't mention (and it's probably causing you problems): you need to make it explicit that you are using a template T above your << overload:

template < typename T>
friend std::ostream& operator<< (std::ostream& os, LinkedList<T>& list);

Also, remove const if you are planning to modify the LinkedList you pass in.

Here's (roughly) what your LinkedList.h should look like:

template <typename T>
struct Node{
    T info;
    Node<T> *next;
};

template <typename T>
class LinkedList
{
    Node<T> *start;
    Node<T> *current;
public:
    LinkedList();
    ~LinkedList();

    template < typename T>
    friend std::ostream& operator<< (std::ostream& os, LinkedList<T>& list);


};

template <typename T>
LinkedList<T>::LinkedList()
{
    start = NULL;
    current = NULL;
}

template <typename T>
LinkedList<T>::~LinkedList()
{
    // Add code.
}

template <typename T>
std::ostream& operator<<(std::ostream& os, LinkedList<T>& list) {
    list.current = list.start;
    while (list.current != NULL)
    {
        os << list.current->info << " -> ";
        list.current = list.current->next;
    }
    os << "NULL" << endl;
    return os;
}    

P.S.

May I suggest that you use nullptr instead of 0 or NULL? It is a new C++11 syntax and has a few benefits (read about it if you want).

Hope this helps!

0
Emilio Garavaglia On

Apart very pathological cases, an "ouptut" operation should not alter the value to be output, so the proper function prototype shold be

template<class T>
std::ostream& operator<<(std::ostream& s, const LinkedList<T>& list)
{
...
}

and you should not assign new values to list members (like in list.current = list.start). You had better to rethink the logic as well...

Also, template function must be implemented in headers, not cpp files