Programming is a hard task that can become overwhelming as systems grows and more dependencies and different libraries, and internal and external code are used together to execute the many tasks needed by the resulting software. In order to reduce this complexity, there are many coding guidelines to help us – which one of them is “make your API easy to use correctly, hard to use incorrectly”. Careful planning and functionalities “blocking” can make a project to proceed smoothly, where it would be a nuclear insanity reactor otherwise.
There are many techniques and idioms to try to make a class hard to misuse in C++ (and many other languages), but the focus of this post is on a specific concept: controlling who can access the private methods of which classes. I’ll talk about one way of achieving this.
This private access control can be really useful. Let’s say, for example, that you have a class that can be publicly used. However, for reasons like instances tracking or resources management, you want it to be instantiated only by a specific Factory and consumed only by a certain type. This can be achieved by making the constructor private, and then using friend methods or classes.
In the above example, we have the medicine class. It’s constructor and Consume methods are both private, so they’re accessible only to both friend classes: MedicineFactory and SickPerson. No other classes can instantiate a medicine or consume it. But there is a catch: since they’re friend classes, it is then possible that, by accident or misinformation, a MedicineFactory end up accidentally consuming a medicine or, even worse, a SickPerson to home brew medicine.
What we want to do here is to make sure that only MedicineFactory instantiates medicine, and only SickPerson consumes it. Of course, a solution that wouldn’t get in the way of helping methods and classes such as std::make_unique or std::make_shared is a plus. There are ways to handle this situation, but I’ll focus on the Passkey Idiom. This idiom allows us to make methods callable only by instances of classes that can instantiate a given key. Using classes as keys, the Medicine class could be written as:
What changed is that now the constructor and Consume method both have a new parameter.As long as we can guarantee that only MedicineFactory can instantiate PasskeyIdiom
The trick lies within the PasskeyIdiom class template:
The three constructors, the destructor and the assignment operator are all defaulted on private accessibility. The “friend T” constructor, possible from C++ 11 onwards, makes it so that only instances or static methods of T can instantiate or uses new objects from the idiom, specialized to T itself. It works quite well – even with smart pointers.
Here’s a full code testing the idiom:All code in this page has been colored by hilite.me.