Search code examples
c++overloadingostream

C++ - ostream, friends and namespaces


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!


Solution

  • 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.