
Hi Scott, Scott Meyers wrote:
I have a question about library interface design in general with a strong interest in its application to C++, so I hope the moderators will view this at on-topic for a list devoted to the users' view of a set of widely used C++ libraries. In its most naked form, the question is this: how important is it that class constructors ensure that their objects are in a "truly" initialized state?
I've always been a big fan of the "don't let users create objects they can't really use" philosophy. So, in general, I don't like the idea of "empty" objects or two-phase construction. It's too easy for people to make mistakes. So, for example, if I were to design an interface for an event log that required a user-specified ostream on which to log events, I'd declare the constructor taking an ostream parameter (possibly with a default, but that's a separate question, so don't worry about it):
EventLog::EventLog(std::ostream& logstream); // an ostream must be // specified
One-phase construction that establishes the class invariant is the one of the two main benefits of OO programming (the other being polymorphism). So I rate it as very important. As for testability, then things like the strategy pattern helps a lot. In your example above, the argument is passed by refernce and so you could perhaps use a dummy class derived from std::ostream. For tightly coupled code (and otherwise), DbC is indispensible. Michael Feathers describes a range of techniques for writing test for legacy code in "Working effectively with legacy code". cheers Thorsten