Overloading the stream insertion (<<) operator for a class

前端 未结 3 1033
野性不改
野性不改 2021-01-23 06:50

It is often overloaded as a friend function of the class. Is there any way it can be overloaded as a member function?

相关标签:
3条回答
  • 2021-01-23 07:13

    If you wanted to badly enough, you could use a member function overload, but it's directly contrary to convention, so doing it would lead to confusion. It would also prevent chaining extraction/insertion operators, and wouldn't work for reading/writing primitive types.

    The reason behind this is that invoking an operator overloaded as a member function means that x << y; is interpreted as x.operator<<(y);, so the overloaded operator has to be a member of the left operand, not the right. It's possible to do that (iostreams include such overloads for some types), but it's essentially impossible to extend (all such overloads have to be part of the iostream object when it's the left operand).

    If you want to overload it as a member of the object to be read/written, you need to put the object being read/written as the left operand. This means insertion would go from left to right instead of right to left. To have at least some chance of maintaining sanity, you'd almost certainly want to use >> for insertion, and << for extraction:

    class my_class {
        int x;
    public:
        bool operator<<(std::istream &is) { 
            // Note the reversal here. That's because we're defining this 
            // for a `my_class` on the left, and an iostream on the right, 
            // but the existing `>>` and `<<` use the reverse of that (iostream
            // on the left).
            is >> x;
            return is.good();
        }
        bool operator>>(std::ostream &os) { 
            os << x;
            return os.good();
        }
    };
    
    my_class a;
    
    a >> std::cout;
    
    a << std::cin;
    

    Note: I'm providing this answer only to point out that it's technically possible to do this, and show how. If you were starting over with a clean slate and you were really set on using member functions, I can see where you might conceivably choose this method--but even then, it's open to a lot of question.

    In particular (as noted above) this would not support chaining. Since the insertion and extraction are done as member functions of the left operand, it also means it would only work for user-defined types, not any primitive types (int, short, long, float, double, bool, etc.)

    Bottom line: if you want to badly enough, you can get it to work to a limited degree under limited circumstances--but neither well (no chaining) nor universally (no primitive types).

    0 讨论(0)
  • 2021-01-23 07:16

    Is there any way it can be overloaded as a member function?

    No. The signature of the function prevents this option.

    // Binary operator where the stream object is left of '<<' and the object
    // instance is right of '<<'
    std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)
    

    For illustration here's a binary operator+ as a free function:

    class Foo
    {
    };
    
    Foo operator+(const Foo& lhs, const Foo& rhs)
    {
        // an appropriate implementation
    }
    
    int main()
    {
        Foo f1;
        Foo f2;
    
        // Uses the free function
        Foo result = f1 + f2;
    
        return 0;
    }
    

    However implemented as a member function it looks like this:

    class Foo
    {
    public:
        Foo operator+(const Foo& other) const
        {
            // an appropriate implementation
        }
    };
    
    int main()
    {
        Foo f1;
        Foo f2;
    
        // The calling sequence is the same as before however 'f1' is logically
        // the same as 'lhs' in the free function implementation example (i.e.,
        // the first type in the binary operator must be the class type when
        // implemented as a member function)
        Foo result = f1 + f2;
    
        return 0;
    }
    

    Given the operator+ member function example it is easier to see why the std::ostream& operator<<(std::ostream& lhs, const Foo& rhs) free function cannot be converted to an equivalent member function. Because 'lhs' would need to be the same type as std::ostream but this is only possible when implementing that class whereas in this example the Foo class is being implemented.

    0 讨论(0)
  • 2021-01-23 07:20

    Is there any way it can be overloaded as a member function?

    Let's say if you have a class Foo and you want to use:

    Foo foo;
    std::cout << foo;
    

    No, it cannot.

    A member function overload works only if the first argument is an object of the class. In the case of stream insertion operators, the first argument is a stream, not an object of the class.

    If you want to use:

    Foo foo;
    foo << std::cout;
    

    Yes, it can be defined as a member function.

    A non-member function and a virtual member function can be combined to good effect when used in a situation where derived classes are involved.

    struct Shape
    {
       // Member function that can be overridden by derived classes.
       virtual std::ostream& operator<<(std::ostream& os) const = 0;
    };
    
    // Non-member function that makes use of member functions.
    std::ostream& operator<<(std::ostream& os, Shape const& shape)
    {
       return shape << os;
    }
    
    struct Rectangle : public Shape
    {
       virtual std::ostream& operator<<(std::ostream& os) const
       {
          // Do the need full to stream a Rectangle.
          // ...
          return os;
       }
    };
    
    struct Ellipse : public Shape
    {
       virtual std::ostream& operator<<(std::ostream& os) const
       {
          // Do the need full to stream an Ellipse.
          // ...
          return os;
       }
    };
    

    Usage:

    Rectangle r;
    Ellipse e;
    
    std::cout << r << std::endl;
    std::cout << e << std::endl;
    
    0 讨论(0)
提交回复
热议问题