views:

173

answers:

3

Since class friendship is not inherited in C++, what's the best way to "fake" it?

I was thinking about exposing the friend class's private interface through protected methods in the to-be-inherited base-class, but that results in having to write (and maintain) the same interface twice.

Are there any other ways?

+6  A: 

The use of a key is a possible solution.

The idea is that you can unlock the operations only if you have a key... but an example is worth thousands on word so let's dive:

// Step 1: The key
class NeedAccess;

namespace details { class Key { friend NeedAccess; Key() {} }; }

// Step 2: NeedAccess
class NeedAccess
{
protected:
  static details::Key GetKey() { return details::Key(); }
};

// Step 3: The big one
class BigOne
{
public:
  void lockedMethod(details::Key);
};

The matter of key being copy constructable is up to discussion. I don't see what you can gain by preventing it.

Another benefit is that you can have several keys, depending on which method you want to access, this way you grant 'partial' friendship, and your 'partial' friends can't mess around with your private parts, despite the famous claim!

EDIT:

This method is called Limited Friendship, and was discussed on comp.lang.c++.moderated.

The main advantage of this method in comparison to Private Interface, is the loose coupling, since only forward declarations are necessary.

Matthieu M.
Since `Key` is an empty class, does it actually have any stack-wize/memory-wize effects, or does the compiler treat it as "syntactic-sugar" only?
sold
An empty class still 'weighs' something (at least a byte worth of data, often more due alignment issues). There is an optimization called Empty Base Optimization, which consists of inheriting from the empty class to avoid incurring this overhead. You could thus choose to have `NeedAccess` inheriting privately from `Key` and return a reference instead of a copy... but a reference also 'weighs' something.
Matthieu M.
A: 

Not sure if this isn't what you're already thinking about but here's a Virtual Friend example

Mattias Nilsson
+2  A: 

The children of the class with frinedship need to ask there parent to do the access for them.

class CrustyNeighbour
{
    private:
       friend class Bob;
       void useWiFi(std::string const& data);
};

class Bob
{
    protected:
        useWifi(CrustyNeighbour& neighbour,std::string const& data)
        {  neighbour.useWiFi(data);}
};

class Mary: public Bob // Bob's offspring
{
     void playHalo(WifiOwner& owner) // WifiOwner derived from CrustyNeighbour
     {
         useWifi(owner,gameData);  // use wifi via his/her parent who access to eighbours wifi
     }
};
Martin York
+1 for your example. :-)
Tenner