Search code examples
c++namespacesoperator-overloadingostream

Overloading ostream operator (<<) for class defined within a namespace


Consider bar.h:

#include <iostream>

namespace foo {

class Bar {
 public:
  friend std::ostream& operator <<(std::ostream& output, const Bar&);
 private:
  int xx_;
};

}

Consider bar.cc:

#include "bar.h"

std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {

  output << in.xx_ << std::endl;

  return output;
}

Why can't the implementation for operator << access the private member from the Bar class? That is:

$ icpc -c bar.cc
bar.cc(5): error #308: member "foo::Bar::xx_" (declared at line 9 of "bar.h") is inaccessible
    output << in.xx_ << std::endl;
                 ^

compilation aborted for bar.cc (code 2)

I solved the problem by embedding the implementation for operator << inside the foo namespace, i.e.:

namespace foo {
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {

  output << in.xx_ << std::endl;

  return output;
}
}

Yet... is this the correct way of solving this problem? Isn't this approach giving away details of the implementation?


Solution

  • Question:

    is this the correct way of solving this problem?

    Answer:

    Yes, it is the correct way of solving the problem.

    Question:

    Isn't this approach giving away details of the implementation?

    Answer:

    Not at all.

    The line

    friend std::ostream& operator <<(std::ostream& output, const Bar&);
    

    declares the function as an external function in the namespace in which the class is defined. If the class is not defined in a namespace, the function is declared as an external function in the global namespace. Since the function is declared as a external function in the foo namespace, it MUST be defined in that namespace.

    If you want that function to be a global function, outside the foo namesapce, you have to use:

    namespace foo
    {
        class Bar;
    }
    
    std::ostream& operator <<(std::ostream& output, const foo::Bar&);
    
    namespace foo {
    
       class Bar {
          public:
             friend std::ostream& operator <<(std::ostream& output, const Bar&);
          private:
             int xx_;
       };
    }