C++ friend

Started by
5 comments, last by DoctorGlow 12 years, 5 months ago
Trying to solidify the concept of the friend keyword in C++.

Seems like there are a few ways to use it.

class Cat
{
friend class Dog;
private:
int age;
};

If the class Dog contains an instance of class Cat it can now access Cat's protected/private data without needing public accessor methods.

If instead it were something like

friend void Dog::DoSomething()

Then only in the method DoSomething would Dog be able to access Cat's protected/private data.

And last if it was something like

class Cat
{
friend void PrintAge(Cat& cat) {cout << cat.age << endl;}
private:
int age;
};

This method is like a static method that can be called without an instance of the class and can access the instances private data. I'm not noticing a difference here between a static and friend function other than the friend function is global and the static version needs a full declaration such as Cat::StaticFunction(). Could anyone explain?


Thanks!
Advertisement

class Cat {
friend void PrintAge(Cat& cat) {cout << cat.age << endl;}
private:
int age;
};


Someone correct me if I'm wrong, but friend seems redundant and useless for a member function. Also, the method is not static because it has not been declared as such. You still need a Cat object to call it from, even though it works on a different Cat object.
Interesting, so the following won't work

class Cat
{
friend void Hello() {cout << "Hello" << endl;}
};

int main()
{
Hello();
}


but this does work

class Cat
{
friend void Hello(Cat& cat) {cout << "Hello" << endl;}
};

int main()
{
Cat cat;
Hello(cat);
}

So it somehow uses the parameter passed in to call the method?
I most commonly use friend for a C callback. ie

[source lang="cpp"]
class Cat
{
private:
friend int ApiCallback(void *);
void OnCallback();
};
[/source]

thus, my ApiCallback can do stuff with Cat
[source lang="cpp"]
int ApiCallback(void *userPtr)
{
((Cat*)userPtr)->OnCallback();
}
[/source]

In your example, your friend declaration has created an in-place, (inline?) function, which is *not* a member of the class but *has* inherited the privacy of the class at that stage. In the first example, you can demonstrate this with the following code:

[source lang="cpp"]
class Cat
{
friend void Hello() {cout << "Hello" << endl;} //implicitly private
public:
static void CallHello() { Hello(); }
};

int main()
{
Cat::CallHello(); //this works
Cat::Hello(); //this doesn't
Hello(); //nor does this
}
[/source]

My guess is that your second example ( [color="#1C2837"]Hello(Cat& cat) ) works because it references the class, so the compiler defers compilation of the inline function until after the class declaration has completed, causing it to then correctly identify it as not subject to the class privacy constraint.

So in short, it seems non-standard and so probably compiler specific in how it works (I tested on VS2010, which compiler are you using? Maybe it works differently with gcc?)


class Cat {
friend void PrintAge(Cat& cat) {cout << cat.age << endl;}
private:
int age;
};


Someone correct me if I'm wrong, but friend seems redundant and useless for a member function. Also, the method is not static because it has not been declared as such. You still need a Cat object to call it from, even though it works on a different Cat object.
Okay, well FYI you're wrong.

friend has about the same effect as static here, the difference being that it allows the method to be placed inside the class body. Just like when using static, an instance is not required to call the method on, although typically one would make one of the parameters to that method be an instance of that class, as shown above.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Okay so in this case friend and static are very similar. I think friend is a bit cleaner since it doesnt require scope resolution operator each time. (Although some may be against it since it could be confusing as to where that method is defined)

Thanks guys!

P.S. I'm thinking the cleanest use for this is to override the ostream/istream operators.

friend ostream& operator<<(ostream&, Cat&);








[font="Consolas"] [/font]
Maybe of relevance Friends.

This topic is closed to new replies.

Advertisement