简体   繁体   中英

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?

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;
}

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.

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; // !!

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);
#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.

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. 

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