Wednesday, April 30, 2008

c++: friend classes in namespaces

You can declare friend class w/o declaration of it:

class A{friend class B;}
Here compiler doesn't have to know what is class B. But things go worth if you have class A defined in namespace N and class B in namespace M, or in other words A and B are in different namespaces. If you leave the things and you don't want to include header with declaration of class B, compiler will argue that class M::B doesn't have an access to private/protected members of N::A. You can't simply do
namespace N{ class A{friend class M::B;} };
Here compiler will raise an error that there is no B in namespace M, or even no such namespace 'M' if it hasn't achieved it during parsing. The solution here is to do a declaration of empty class B in namespace M:
namespace M{class B;}; namespace N{ class A{friend class M::B;} };
This will work and your compiler will be happy ;)

8 comments:

Cheba said...

What's the point of nonexistent friend class declaration? Imaginary friend?

BTW, what is friend class?

Ni@m said...

Friend class can access private and protected members of the current class. Also function can be a friend.

The class doesn't have to know about it's friend. It doesn't use anything from it. So compiler doesn't have to know what is friend class while it's parsing the class declaration. When you declare friend and specify the namespace where friend is located, it looks like compiler tries to expand that namespace and find the actual class or function.

But when you try to access namespace different from current, compiler

Dean said...

Fantastic! Thought i was clearly missing something when trying to access private members cross-namespace!

Thanks again, exactly the answer i needed.

Ni@m said...

Hello, Dean!
I'm glad you've found this interesting.

Xing said...

Yes, very useful and exactly what I needed for my current code.

I have to say, the syntax is ugly, thought, c++ compilers need to be more clever handling this issue itself.

Ni@m said...

Xing, I also thought that this should be recognized by smart compilers. To be honest I don't understand why this couldn't be done since in one parent namespace there couldn't be namespace and class with same name.

Brian said...

But what if you're already nested inside a namespace, and the autogeneration tool is being a jerk?

namespace A{
namespace B{

--- insert prototype here ---

class ProductionClass
{
friend class A::C::HelperClass;
}

};};


Meanwhile the target is in
namespace A{
namespace C{
class HelperClass;
};};


I can't seem to get a working solution without circumventing the generator. What would the prototype look like?

Ni@m said...

Brian, in your case you have to modify the generator. I should insert
namespace C {
class HelperClass;
};
inside the namespace A before ProductionClass class declaration. I suppose the generator while it is in namespace A loop over nested classes and find their friends. If friend inside namespace A - put the friend class declaration.
Worth to mention that multiply class declaration is not a problem. The following code is ok:
namespace A {
namespace B {
class C;
};

namespace B {
class C;

class D {
friend class A::B::C;
int d;
};
};
};

However the code is not clean but the generation tool should not be very smart though.