Private Interfaces

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 friend keyword.

Here's an example:
1
2
3
4
5
6
7
8
9
10
11
//MoveReceiver.hpp

struct Position;
struct GamePiece;

struct MoveReceiver
{
    virtual ~MoveReceiver() = default;
    virtual void addMove(GamePiece &piece, Position const &m) = 0;
    virtual void removeMove(GamePiece &piece, Position const &m) = 0;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//GameBoard.hpp

#include "MoveReceiver.hpp"

#include <memory>
#include <set>
#include <map>

struct GameBoard : private MoveReceiver
{
    void addPiece(Position const &p);
    //...

private:
    std::set<std::unique_ptr<GamePiece>> pieces;
    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;
};
1
2
3
4
5
6
7
8
9
//GamePiece.hpp

#include "GameBoard.hpp"

struct GamePiece
{
    GamePiece(MoveReceiver &mr);
    //...
};
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 GamePieces. 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 GamePieces. If needed, each GamePiece can be made aware only of the Positions of other GamePieces 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?
Last edited on
No one has comments on this? I assume it just got buried at a bad time or something?
Last edited on
What problem did it solve?
MatthewRock wrote:
What problem did it solve?
What problems do private variables solve?

I think that data access and interface access should be treated the same way.
L B wrote:
...this means that any code that has access to an instance of the class also has access to all the interfaces the class implements.

That's good. That's how it should be. (Well, it may manipulate objects of the class through any interface that the class implements.)

L B wrote:
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.

Then that code should only get a reference that has the interface type, not of the actual implementation class.
Last edited on
booradley60 wrote:
Then that code should only get a reference that has the interface type, not of the actual implementation class.
The point is that having the implementation type should not grant access to the privately implemented interface.
I'd say that people say that it has limited uses, because... it has limited uses. It's nice to organize your data, but it's not something as useful as, let's say, templates. At least that's what I think about it.
I think that because C++ is one of the only languages where it's possible, it just hasn't been explored enough to know whether it is useful or not.

I do still want opinions on this from more people, which is why I am bumping this.
Hi LB,

As per usual I am only replying because my critical thinking has kicked in, so forgive me if I have misunderstood something.

Just wondering how this is different to making addMove and removeMove protected in the base class?

They both effectively become private which is the same thing, and MoveReceiver is abstract anyway.

IMO this use of private inheritance could be a sledgehammer: Everything becomes private, as opposed to the use of protected in the base class which allows one to choose which ones will be effectively private in derived classes.

Also private inheritance has the effect of "stopping" nearly everything from any further inheritance (unless derived classes introduce additional stuff - might be unlikely), so a privately inherited class would often be marked final as you have done. This could be a problem as there might be lots of examples where further inheritance is required. I am thinking of a Role Play Game, where one can imagine lots of different sub-types of enemies, weapons and compatriots etc.

closed account (N36fSL3A)
TheIdeasMan wrote:
I am thinking of a Role Play Game, where one can imagine lots of different sub-types of enemies, weapons and compatriots etc.
Well if you're making a RPG (or any game really) you should abandon game object inheritance and probably use a component-based design.
Last edited on
@Fredbill

Ok, maybe it was a bad example: my point was that private inheritance is awkward if further inheritance is required.

This doesn't only apply to games: I am doing some C++ with AutoCAD, there are at least 5 layers of inheritance going on there.
TheIdeasMan wrote:
Just wondering how this is different to making addMove and removeMove protected in the base class?

They both effectively become private which is the same thing, and MoveReceiver is abstract anyway.
Did you look at the example? The private interface is not intended for the deriving class.
TheIdeasMan wrote:
Also private inheritance has the effect of "stopping" nearly everything from any further inheritance (unless derived classes introduce additional stuff - might be unlikely), so a privately inherited class would often be marked final as you have done. This could be a problem as there might be lots of examples where further inheritance is required.
I don't see where the problem is - none of the classes are final, and this does not hinder normal inheritance in any way.
Topic archived. No new replies allowed.