For my library, I want to expose a clean public API that does not distract with implementation details. As you have it, though, these details are leaking even to the public realm: Some classes have valid public methods that are used by the rest of the library, but aren't very useful for the user of the API and as such don't need to be a part of it. A simplified example of the public code:
class Cookie;
class CookieJar {
public:
Cookie getCookie();
}
class CookieMonster {
public:
void feed(CookieJar cookieJar) {
while (isHungry()) {
cookieJar.getCookie();
}
}
bool isHungry();
}
The getCookie()
method of a CookieJar
is not useful to the user of the library, who presumably does not like cookies anyway. It is, however, used by the CookieMonster
to feed itself, when given one.
There are some idioms that help solve this issue. The Pimpl idiom offers to hide the private members of a class, but does little to disguise the public methods that are not supposed to be a part of the API. It is possible to move those into the implementation class as well, but you would then need to provide direct access to it for the rest of the library to use. Such a header would look like this:
class Cookie;
class CookieJarImpl;
class CookieJar {
public:
CookieJarImpl* getImplementation() {
return pimpl.get();
}
private:
std::unique_ptr<CookieJarImpl> pimpl;
}
It is handy if you really need to prevent user access to these methods, but if it's merely an annoyance, this doesn't help very much. In fact, new the method is now even more useless than the last, because the user does not have access to the implementation of CookieJarImpl
.
An alternative approach is to define the interface as an abstract base class. This gives explicit control over what is a part of the public API. Any private details can be included in the implementation of this interface, which is inaccessible to the user. The caveat is that the resulting virtual calls impact performance, even more so than the Pimpl idiom. Trading speed for a cleaner API is not very attractive for what is supposed to be a high performance library.
To be exhaustive, yet another option is to make the problematic methods private and use friend classes where needed to access them from the outside. This, however, gives the target objects access to the truly private members as well, somewhat breaking encapsulation.
So far the best solution to me seems to be the Python way: Instead of trying to hide the implementation details, just name them appropriately, so that they are easily identifiable as not part of the public API and do not distract from regular usage. The naming convention that comes to mind is using an underscore prefix, but apparently such names are reserved for the compiler and their use is discouraged.
Are there any other c++ naming conventions for distinguishing members that are not intended to be used from outside the library? Or would you instead suggest me to use one of the alternatives above or something else I missed?