ABI Stability Is Difficult
It’s easy to break the ABI of a C++ class. Just add a new member variable to a public class or add a member variable to an implementation class that’s used a a member instance in a public class. C has the same problem, though it’s not quite as bad because they tend to use pointers more rather than member instances.
I have mostly had the luxury of working in these two situations:
- The code is used by a closed group of people, who expect to rebuild their entire set of software often.
- The code is open source, even during its development, so the API and ABI can become quite mature before it is declared ABI stable. However, there are still things that I wish I could change now.
But what if it’s a toolkit whose first public version will be released as ABI-stable?
Pimpl?
Pimpl is the only real solution that I know of. You use an opaque pointer as a member variable. The class to which the pointer points is not fully defined in the header. For instance:
class PrivateThing; class Something { ... private: PrivateThing* m_priv; };
The instance of PrivateThing is then created in the Something constructor.
This has some disadvantages:
- It requires more runtime allocation of memory, in more pieces, which is slow.
However, I wonder whether this is significant in the average application, given that the public class is probably a member of something that’s allocated dynamically anyway. - It causes a slight slowdown, because an extra dereference is necessary whenever the member data is accessed.
This might not be significant. - It makes the code less easy to read, and adds repetitive code to each class method.
- You cannot provide protected (rather than private) members for use in derived classes while simultaneously hiding those members.
Many would say this is a good thing. I would probably make m_priv protected though, so that derived classes in the toolkit itself can access members directly, with their knowledge of its definition, while preventing use from applications.
I am fairly confident that this is the best solution, particularly as it’s equivalent to what GTK+ does in C. But please do comment if you have opinions or alternatives.