0

compilation error when I overload cout operator inside the class

What I am missing?

Here after the source code. The problem disappear when I define the overload operator outside the class

#include <iostream>
using namespace std;

class Box {
    public:
                int l, b, h;
        Box(int length, int breadth, int height) : l(length), b(breadth), h(height) {}
#if 1
        ostream& operator<<(ostream& os) {
            os << (l * b * h);
            return os;
        }
#endif
};

#if 0
ostream& operator<<(ostream& os, Box inb) {
    os << (inb.l * inb.b * inb.h);
    return os;
}
#endif


int main(void) {
    Box B(3,4,5);
        cout << B << endl;
    return 0;
}
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • 3
    That is not how to overload the `operator<<` in either case. See [here](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – ChrisMM Dec 04 '19 at 13:52

3 Answers3

5

The member function:

ostream& operator<<(ostream& os);

would be useful in this case:

boxobject << os;

which is rarely what you want to do. Instead, you need this free function:

std::ostream& operator<<(std::ostream& os, const Box& inb) {
    os << (inb.l * inb.b * inb.h);
    return os;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • does not compile. but if I add friend keyword then the compilation works fne – MOHAMED Dec 04 '19 at 14:35
  • @MOHAMED If that's the case, your real `Box` definition is not like what you put in the question. If you use the `Box` definition as it is in the question, it works without `friend`: https://godbolt.org/z/e9zdhX - But sure, making `operator<<` a friend is common - or if you already have public accessors for `l`, `b` and `h` you can use those in `operator<<` if you don't want to make `operator<<` a friend. – Ted Lyngmo Dec 04 '19 at 15:08
1

You can't overload operator << that way and have it work like normal. When you have

ostream& operator<<(ostream& os) {
    os << (l * b * h);
    return os;
}

What you really have is

ostream& operator<<(Box& this_, ostream& os) {
    os << (this_.l * this_.b * this_.h);
    return os;
}

Which means you would need to call cout like

B << cout << endl;

The reason for this is that all class member functions have an implicit parameter of a reference type to the class as their first parameter. The compiler inserts this for you as that is how the member function knows which object to work on.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

The expression X << Y (when at least one operand has class or enum type) looks for whether operator<<(X, Y) or X.operator(Y) can be called.

So in cout << B, it looks for operator<<(cout, B) and cout.operator<<(B). Notice it's not at all looking for members of B. It looks for members of cout, but you can't add new members to a standard library class. So you need to define the non-member function.

The member you did define would make B << std::cout << std::endl; work, but that doesn't look right, obviously.

One other option, necessary if the operator needs to use private members of the class, or nice if we just want the operator visible in the class's public section, is to declare it a friend, which is really a non-member:

class Box {
public:
    Box(int length, int breadth, int height) : l(length), b(breadth), h(height) {}

    friend std::ostream& operator<<(ostream& os, const Box& box) {
        os << (box.l * box.b * box.h);
        return os;
    }

private:
    int l, b, h;
};
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • the variables are public in my class. I used your function but still does not work. I added friend keyword and the compilation work now – MOHAMED Dec 04 '19 at 14:35
  • @MOHAMED I don't understand your comment (or the comment you made to my answer). This answer already makes it a `friend`. Where did you add the `friend` keyword to this answer exacly? – Ted Lyngmo Dec 04 '19 at 17:26