I was looking through some C++ code written by a (now departed) coworker quite a long time ago, and found an odd class definition I’m trying to decipher.
class BaseClass
{
friend SubClass1;
friend SubClass2;
}
class SubClass1 : public BaseClass
{
...
}
class SubClass2 : public BaseClass
{
...
}
Is there a benefit to designing a class hierarchy this way? If you want access to private methods of BaseClass from the subclasses wouldn’t you just move them to protected instead of private? I feel there is an idiom I’m missing here.
It is hard to say without looking at the real design of the library, but the two approaches are not equivalent. Using
friendin this way provides greater access to lesser types than you can get by declaring all membersprotected.Greater access
The meaning of
protectedis not exactly grant access to all base members everywhere to the derived type, but rather grant access to the protected members of the base subobject inside the derived type. The difference is that a derived type cannot access protected members or a type that is not of its own type or derived types.Consider two versions of a class one of which has all members protected and no friend declaration, another that has all members private and declares a subclass as a friend. Now consider that the derived type had a function:
In the case of using
protected, the issue there is thatprotecteddoes not let you tweak the contents of any object other thanderivedor types derived fromderived, but the argument could be abaseor any other type that extendsbaseand it not otherwise related toderived.This restriction is a bit less clear in some other use cases, and you might be able to obtain access to those protected members outside of your own hierarchy, just not in a direct simple way (I consider that a bug in the access specifier specification of the language).
On the other hand, if
derivedis a friend of thebasethe above code will compile, asderivedis granted access to everybaseinstance anywhere, be it a subobject ofderivedor not.To lesser types
The
protectedaccess specifier is transtive, once you grant access throughprotectedto a derived type, you are granting it to all types that derive from it, and also to any other type that might inherit directly from you. It is impossible to control what types are granted access and which are not. On the other hand friendship is precise, only the members of the types declared as friend will have access. Friendship is not transitive, so type other than your declared friends will have access.