As I was saying last post, the provision of a default constructor when a class doesn't naturally lend itself to being configurationless means that you'll end up having to support a weakened invariant which will both make your class more awkward to reason about and harder to maintain.
But sometimes it is necessary for a default constructor to be provided, as jogobom pointed out.
There are APIs out there which rely on being able to default construct objects. Qt has already been mentioned. COM, ATL and MFC are three others. I myself have written a framework in the past which required it, and then ended up having to invent workarounds for classes for which it would be prohibitive to provide one.
No matter how rude it is for those frameworks to require you to bend your classes to their will, and it is undoubtedly rude, the fact remains that your code is going to have to change before theirs does.
What are you able to do about it? Well, it's generally not a good idea to try and force a default state into a class that doesn't want it. What we want is to separate the 'real' class from the singular state. That way, the class can continue to be easily maintained and reasoned about, and the singularity can be solely responsible for ensuring it's not accidentally used.
There are a couple of easy ways of achieving that. First, you might consider using a boost::optional. If you're familiar with C# then it's closely related to a Nullable type. This way, you can defer construction of your 'real' object while the Optional ensure correct access to it.
Another option exists if you already employ the Pimpl idiom. This is the layer of indirection you need between construction of the client-facing object and the real implementation. You just need to defer allocation of the 'impl' and constrain access to it.
Examples coming soon.
No comments:
Post a Comment