Devesh Agrawal
Devesh Agrawal

Reputation: 9212

How to overload << operator without friend function

I am trying to overload << operator to print Currency (user defined type)

#include <iostream>
using namespace std;

struct Currency
{
  int Dollar;
  int Cents;

  ostream& operator<< (ostream &out)
  {
    out << "(" << Dollar << ", " << Cents << ")";
    return out;
  }
};



template<typename T>
void DisplayValue(T tValue)  
{
   cout << tValue << endl;
}

int main() {

Currency c;
c.Dollar = 10;
c.Cents = 54;

DisplayValue(20); // <int>
DisplayValue("This is text"); // <const char*>
DisplayValue(20.4 * 3.14); // <double>
DisplayValue(c); // Works. compiler will be happy now. 
return 0;
}

But getting the following error.

prog.cpp: In instantiation of ‘void DisplayValue(T) [with T = Currency]’:
prog.cpp:34:16:   required from here
prog.cpp:22:9: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
    cout << tValue << endl;
         ^
In file included from /usr/include/c++/4.8/iostream:39:0,
                 from prog.cpp:1:
/usr/include/c++/4.8/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Currency]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

Can anyone help me if i am missing any thing or doing anything wrong here?

Upvotes: 2

Views: 22253

Answers (6)

satinder singh
satinder singh

Reputation: 310

#include<iostream>
using namespace std;
class myclass
{
    int x;
    public:
    myclass() //constructor
    {
        x=5;
    }

    friend ostream& operator<<(ostream &outStreamObject,myclass &object); //standard way

    void operator<<(ostream &outStreamObject) //Another way.
    {
        outStreamObject<<this->x;
    }


};
 ostream& operator<<(ostream &outStreamObject,myclass &object)
{
    cout<<object.x;
    return outStreamObject;
}
int main()
{
    //standard way of overload the extraction operator
    myclass object1,object2;
    cout<<object1<<" "<<object2;
    cout<<endl;
    //overloading the extraction operator with using friend function
    object1.operator<<(cout);
    return 0;
}

It is not at all necessary that the insertion and the extraction operators can be overloaded only by using the friend function. The above code overloads the extraction operator with and without the friend function. The friend function implementation is favoured because cout can be used the way it is used for other datatypes. Similary you can overload the insertion operator.

Upvotes: -1

Loki Astari
Loki Astari

Reputation: 264331

First you need to fix the operator by adding Currency const& c as the second parameter (as it come s on the right hand side).

Then you have two options:

1: Add Friend

struct Currency
{
  int Dollar;
  int Cents;

  friend ostream& operator<< (ostream &out, Currency const& c)
  {
    return out << "(" << c.Dollar << ", " << c.Cents << ")";
  }
};

2: Move the definition outside the class

struct Currency
{
  int Dollar;
  int Cents;
};

ostream& operator<< (ostream &out, Currency const& c)
{
  return out << "(" << C.Dollar << ", " << c.Cents << ")";
}

Either works and is fine.
Personally I like option-1 as it documents the tight coupling of the output operator to the class that it is outputting. But this is such a simple case that either works just fine.

The reason that it can not be a member is that the first parameter is a stream (the left hand side value of the operator is the first parameter). This does not work for members as the first parameter is the hidden this parameter. So technically you could add this method to std::ostream. Unfortunately you don't have accesses (and not allowed to) modify std::ostream. As a result you must make it a free standing function.

Example showing it can be a member:

struct X
{
    std::ostream operator<<(int y)
    {
        return std::cout << y << " -- An int\n";
    }
};
int main()
{
    X   x;
    x << 5;
}

That works fine here. This is because the compiler translates

x << 5;

into

// not real code (pseudo thought experiment code).
operator<<(x, 5)
      // Equivalent to:
                X::operator<<(int y)
      // or
                operator<<(X& x, int y) 

Because x has a member function operator<< this works fine. If x did not have a member function called operator<< then the compiler would look for a free standing function that takes two parameters with X as the first and int as the second.

Upvotes: 9

Davlog
Davlog

Reputation: 2238

You need to make it friend : Also you need to give it the right arguments. an ostream and the currency.

  friend ostream& operator<< (ostream& stream, const Currency& c )
  {
    stream << "(" << c.Dollar << ", " << c.Cents << ")";
    return stream;
  }

Edit:
As you can see in the comments, you don't have to make it friend. You can put it outside the structure.

Currency c;
c.Dollar = 10;
c.Cents = 54;

DisplayValue(c); // Works. compiler will be happy now. 

Upvotes: -3

David G
David G

Reputation: 96790

The way you've written your inserter method, the only way to get it to work would be to do:

c << std::cout;

But instead, if you know your inserters won't need to access any private variables, simply do as the other answers say and create a global function that takes both arguments:

std::ostream& operator <<(std::ostream& os, const Currency& c);

Upvotes: 1

Daniel Frey
Daniel Frey

Reputation: 56863

You don't put it into your class, you put if afterwards. Since your members are public there is no need to declare it a friend:

struct Currency
{
    int Dollar;
    int Cents;
};

ostream& operator<< (ostream &out, const Currency& c)
{
    out << "(" << c.Dollar << ", " << c.Cents << ")";
    return out;
}

Upvotes: 8

masoud
masoud

Reputation: 56479

Overload it like below, and put it outside of class declaration (you don't need friendship!):

ostream& operator<< (ostream &out, const Currency &c)
{                                 //^^^^^^^^^^^^^^^^
  out << "(" << c.Dollar << ", " << c.Cents << ")";
  return out;
}

Funny thing with your code is, you have to use the operator like this:

c << cout; // !!

Upvotes: 3

Related Questions