C++ - ostream, friends and namespaces

Sidar picture Sidar · May 2, 2012 · Viewed 9.6k times · Source

Everything was fine until I moved my objects to a namespace. And now the compiler claims that my Color attributes are private.

I thought the whole point of friends was to share encapsulated information with those a class befriends.

Color.h

friend ostream & operator << (ostream& output, const st::Color& color);

Color.cpp:

 ostream & operator <<(ostream& output, const st::Color& color) {

    output << "Colors:\nalpha\t: " << color.a << "\nred\t: "  << color.r << "\ngreen\t: " << color.g
            << "\nblue\t: " << color.b <<  "\nvalue\t: " << color.color();

    return output;
}

error:

Color.h||In function 'std::ostream& operator<<(std::ostream&, const st::Color&)':|
Color.h|52|error: 'unsigned char st::Color::a' is private|
Color.cpp|15|error: within this context|
Color.h|49|error: 'unsigned char st::Color::r' is private|
Color.cpp|15|error: within this context|
Color.h|51|error: 'unsigned char st::Color::g' is private|
Color.cpp|15|error: within this context|
Color.h|50|error: 'unsigned char st::Color::b' is private|
Color.cpp|16|error: within this context|
||=== Build finished: 8 errors, 0 warnings (0 minutes, 1 seconds) ===|

So what is the deal? I'm using Code::Blocks as my IDE. And it won't even show any properties or methods when I use the dot operator on the "color" parameter. This is obviously a sign of something going wrong...somewhere.

I've taken the friend operator overloading out and it compiles just fine. No error elsewhere. What gives?

It's declared as follows:

namespace st{

class Color {

    friend ostream & operator << (ostream& output, const st::Color& color);
 public:
     ....
 private:
    .....

};
};

Edit:

In my CPP I've now done this:

namespace st{
ostream & st::operator <<(ostream& output, const st::Color& color) {

    output << "Colors:\nalpha\t: " << color.a << "\nred\t: "  << color.r << "\ngreen\t: " << color.g
            << "\nblue\t: " << color.b <<  "\nvalue\t: " << color.color();

    return output;
}
}

st::Color::Color() {

    reset();
}

st::Color::Color(const Color& orig) {

    a = orig.a;
    r = orig.r;
    g = orig.g;
    b = orig.b;
}

void st::Color::reset() {
    a = 0;
    r = 0;
    g = 0;
    b = 0;
}
... etc
}

No compile errors, but is it normal for such a situation to use the namespace again in the header? Or is this completely off from what I should be doing?

Edit: @Rob thanks for your input as well!

Answer

pmr picture pmr · May 2, 2012

You need to declare and define your operators in the same namespace as the object as well. They will still be found through Argument-Dependent-Lookup.

A usual implementation will look like this:

/// header file
namespace foo {
   class A
   {
    public:
    A();

    private:
    int x_;
    friend std::ostream& operator<<(std::ostream& o, const A& a);
    };

    std::ostream& operator<<(std::ostream& o, const A& a);
} // foo

// cpp file
namespace foo {
     A::A() : x_(23) {}

     std::ostream& operator<<(std::ostream& o, const A& a){
     return o << "A: " << a.x_;
    }
} // foo


int main()
{
  foo::A a;
  std::cout << a << std::endl;
  return 0;
}

Edit

It seems that you are not declarin your operator<< in the namespace and are also defining it outside of the namespace. I've adjusted the code.