I haven't seen anything like this in my research, so if this is already a known thing, please link me to the articles on it.
Nearly everyone will tell you that private inheritance has limited uses and is mainly only for composition/has-a relationships and implemented-in-terms-of relationships, but I think everyone is missing out on a big useful feature that comes with private inheritance: private interfaces.
Generally in C++ (and always in Java), interfaces are implemented publicly. However, this means that any code that has access to an instance of the class also has access to all the interfaces the class implements. People will tell you "that's good, that's how it should be", but I disagree - there are definitely cases where I only want a certain interface to my class to be accessible to specific code. Mediator objects sort of accomplish this, but they seem convoluted to me. Why not take the simple approach?
C++ private inheritance is exactly that: a private interface. Only the class implementing the interface is allowed to cast a reference to the class into a reference to the interface, so the class has full control over which code it gives access to that interface to. Obviously, this goes hand-in-hand with tell-don't-ask.
This also allows for much more modular coupling - coupled classes can communicate through their private interfaces and know that only the two interfaces know about each other, and not just arbitrary code. Where a mediator needs to know of all classes/interfaces it mediates, each private interface need only know about the other private interfaces it interacts with, and not all that are involved. There's also no use of the
Here's an example:
virtual ~MoveReceiver() = default;
virtual void addMove(GamePiece &piece, Position const &m) = 0;
virtual void removeMove(GamePiece &piece, Position const &m) = 0;
struct GameBoard : private MoveReceiver
void addPiece(Position const &p);
std::multimap<Position, decltype(pieces)::iterator> moves;
virtual void addMove(GamePiece &piece, Position const &m) final override;
virtual void removeMove(GamePiece &piece, Position const &m) final override;
I assume that is enough information to understand how it works and what is going on, but I can elaborate on anything and provide example implementations of the declared member functions or explain the intended interactions.
Only a GamePiece
should decide which moves it can make, and only a GameBoard
needs to know all valid moves at once. Thus, a GamePiecce
receives the exact interface it needs, and a GameBoard
only gives access to that interface to GamePiece
s. The private interface here is, obviously, MoveReiever
. Yes, one instance of a GamePiece
can submit move instructions for different instances of GamePiece
, but in this example the interfaces are designed such that each GamePiece
has no way to be aware of other GamePiece
s. If needed, each GamePiece
can be made aware only of the Position
s of other GamePiece
s so as to change its moveset accordingly.
Private interfaces solve a lot of problems I've been having with my designs, so I find them very useful. But what do you think?