C++ - ostream, friends and namespaces
Asked Answered
N

2

11

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!

Nisen answered 1/5, 2012 at 22:33 Comment(5)
What do you mean by "moved my objects to a namespace"?Grisly
Moving the object in between a namespace. I.E namespace st{ class... }Nisen
Don't use the namespace again in the definition of operator<<. This should not be necessary.Izolaiztaccihuatl
You mean don't place the definition in the namespace in the header?edit:Sorry I meant CPP not header in the code above.Nisen
add the st namespace declaration around the ostream method in you cpp file. see my answer below (I tried it on Linux with g++ it worked nicely).Request
I
11

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.

Izolaiztaccihuatl answered 1/5, 2012 at 22:34 Comment(8)
Please elaborate on that. Any example? So far the friend is declared witht in the namespace st. It's declared within the Color class.Nisen
@Nisen I added an example. You might want to add code to your question to show your problem.Izolaiztaccihuatl
I'm rather confused, I thought that is exactly what i'm doing. The declaration is set in the cpp file while the definition is in the header. How is that different from your example? I don't really know what to show more. This is really all there is to it.Nisen
I really feel like i'm not following what you are trying to tell me. The declaration is within the object itself.Then I define it in the cpp. Is it of necessity to declare it [again] in the namespace itself in the header? Wouldn't that operator overload become part of the namespace?Nisen
@Nisen If you declare a function as a friend inside a class you also implicitly declare it as a function in the surrounding namespace. It's often best to avoid all this and have a public print function accepting an ostream& and simple make the operator<< in the surrounding namespace forward to this function.Izolaiztaccihuatl
I'm not completely assured, but it works for now I guess. However If it's implicitely declared in the namespace, why have you friend it and declared it again in the namespace? Isn't line 12 in your example redundant now?Nisen
@Nisen Yes, it is. Sorry for the confusion. I added this because I thought it made it clearer where the function actually ends up. Guess I was wrong.Izolaiztaccihuatl
I was having a similar problem when trying to compile a project using g++; clang++ was okay with me only declaring the friend part, but when I tried to compile with g++, it wouldn't work without also declaring std::ostream& operator<<(std::ostream& o, const A& a); in my namespace. Thanks for your answer!Hagiarchy
R
0

You need to qualify your operator with the namespace as well. It is a function signature declared in the name space so to access its symbol you need to prefix it with the namespace.

Try it like this:

namespace st {

    ostream & operator <<(ostream& output, const 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;
    }
}
Request answered 1/5, 2012 at 22:49 Comment(6)
throws me: error: 'std::ostream& st::operator<<(std::ostream&, const st::Color&)' should have been declared inside 'st'Nisen
what compiler are you using? This works in Visual Studio Express 2010. If this does not work then what is sure to work is to put the body of the method in the h file inside the namespace block.Request
GCC. That is what I did. ( look at my edit ) so it would be perfectly fine to use namespace st{} in the header itself again, and only put the operator overload there? I feel like I missed out on this information. Everything else is just scoped with st::Color::Etc.Nisen
try adding the namespace declaration in your cpp as well. like my edit above. it worked for me using g++ on ubuntu VM.Request
My bad, I meant the CPP. What you see above in the edit is the CPP file. While It works, now everytime when I type st:: the operator overload shows up too...Is this how it suppose to be?Nisen
All you are doing is providing a context for the symbold declared within. So it is pretty? no, but it lets the compiler know what ostream operator you are defining and lets you keep the code for the operator out of the h file. It is a matter of choice at this point :). It is legal to reuse the name space declaration as many time as you like think of the std name sapce it covers many files its only purpose is to avoid name colisions between libraries so it is not wrong to use it in this case.Request

© 2022 - 2024 — McMap. All rights reserved.