You've been warned. This is for the code-junkie-at-heart.
I wrote up the story of what refactoring the observer pattern was like here.
These are my favorite (sub-item) tips from Scott Meyers's book, Effective C++ Second Edition. (Now available on CD-ROM, too.) Both of these tips combine templates with inheritance. The first tip shows a class inheriting from a template, and the latter is a template that inherits from a base class.Item 7, Page 32 : A quaint, but useful little tip. Templates can be used to limit the scope of inherited static members.
template<class T> class NewHandlerSupport { ... private: static new_handler currentHandler; // Here's the static member }; class Dog: public NewHandlerSupport<Dog> { // Dog has its own currentHander! ... }; class Cat: public NewHandlerSupport<Cat> { // Cat has its own currentHandler, too! ... };
Now, both Dog and Cat have a static currentHander
, but they're different
currentHandlers!
Item 42, Page 194
: A template inherits a class to limit the explosion of compiler-generated classes (only one copy of the
code is used, that from the base class), with all the type safety
of templates. Assume your standard GenericStack
class exists, then:
template<class T> class Stack: private GenericStack { public: void push(T *objectPtr) { GenericStack::push(objectPtr); } T * pop() { return static_cast<T*> (GenericStack::pop()); } bool empty() const { return GenericStack::empty(); } };
Of this example Scott Meyers writes,
This is amazing code, though you may not realize it right away. Because of the template, compilers will automatically generate as many interface classes as you need. Because those classes are type-safe, client type errors are detected during compilation. BecauseGenericStack
's member functions are protected and interface classes use it as a private base class, clients are unable to bypass the interface classes. Because each interface class member function is (implicitly) declared inline, no runtime cost is incurred by use of the type-safe classes; the generated code is exactly the same as if clients programmed withGenericStack
directly (assuming compilers respect theinline
request - see Item 33). And becauseGenericStack
usesvoid *
pointers, you pay for only one copy of the code for manipulating stacks, no matter how many different types of stack you use in your program. In short, this design gives you code that's both maximally efficient and maximally type safe. It's difficult to do better than that.