Search code examples
c++operator-overloadingoverloadingoperator-keyword

How to overload 2 versions of operator<< in a C++ class


I am overloading operator<< as follows :

std::ostream& operator<<(std::ostream& o, const MyClass& myobj);

Now, I would like to have 2 versions of operator<<, one that would display a short description of my object, and another that would display a longer version.

For example, MyClass could contain information about a client. In the short version I would display just the name, and in the long version I would display more details like birthday, address, etc.

Is there a way to do that in C++ ?

I know I could have a method of MyClass that receives the stream, but it would be called like this :

myObj.DisplayShort(cout)

or

myObj.DisplayLong(cout)

but I would like to stay with a syntax similar to the usual form :

cout << myObj << endl;

Solution

  • The standard way is to create a custom formatting flag and a custom manipulator using std::ios_base::xalloc and std::ios_base::iword.

    So you have

    class MyClass {
       static int fmt_flag_index;
       enum fmt_flag { output_short, output_long };
    }
    

    You initialize fmt_flag_index somewhere at the program startup:

    int MyClass::fmt_flag_index = std::ios_base::xalloc();
    

    Here's your custom formatting flag ready to use. Now IO manipulators can set it:

    std::ios_base& myclass_short(std::ios_base& os)
    {
        os.iword(MyClass::fmt_flag_index) = static_cast<int>(MyClass::output_short);
        return os;
    }
    
    std::ios_base& myclass_long(std::ios_base& os)
    {
        os.iword(MyClass::fmt_flag_index) = static_cast<int>(MyClass::output_long);
        return os;
    }
    

    And operator<< access it:

    std::ostream& operator<<(std::ostream& os, MyClass& f)
    {
       switch (static_cast<MyClass::fmt_flag>(os.iword(MyClass::fmt_flag_index)))
       {
         case MyClass::output_short: ...;
         case MyClass::output_long: ...;
       }
    }
    

    Use it like this:

    MyClass myobj;
    std::cout << myclass_long << myobj;
    std::cout << myclass_short << myobj;
    

    Demo