Through the disciplined and consistent use of comments in the class declaration. For example, each member function can have the following lines just before or just after the declaration:
This technique is illustrated in the following example: class Empty { }; class Full { }; class Stack { public: Stack() throw(); // PURPOSE: Initializes a Stack // REQUIRE: Nothing // PROMISE: size() will be zero unsigned size() const throw(); // PURPOSE: Returns the number of elements on this Stack // REQUIRE: Nothing // PROMISE: Return value will be between 0 and 10 // inclusive int top() const throw(Empty); // PURPOSE: Returns the top element of this Stack // REQUIRE: size() must not be zero // PROMISE: Nothing void push(int elem) throw(Full); // PURPOSE: Pushes elem onto the end of this Stack // REQUIRE: size() must be strictly less than 10 // PROMISE: size() will increase by 1 // PROMISE: top() will be the same as parameter elem int pop() throw(Empty); // PURPOSE: Pops and returns the top element from this // REQUIRE: size() must not be zero // PROMISE: size() will decrease by 1 // PROMISE: Returns the same as if top() were called at // the beginning protected: int data_[10]; unsigned size_; }; inline Stack::Stack() throw() : size_(0) { } inline unsigned Stack::size() const throw() { return size_; } inline int Stack::top() const throw(Empty) { if (size_ == 0) throw Empty(); return data_[size_-1]; } inline void Stack::push(int elem) throw(Full) { if (size_ == 10) throw Full(); data_[size_++] = elem; } inline int Stack::pop() throw(Empty) { if (size_ == 0) throw Empty(); return data_[--size_]; } int main() { Stack s; s.push(42); int elem = s.pop(); } Keeping a class's specification in the header file (for example, the .hpp file) makes it easier for developers to find the specification and keep it synchronized with the code when changes are needed. |