Advice from B.Stroustrup's The C++ Programming Language, 3rd Edition

Chapter 1: Suggestions for C Programmers

  1. Macros are almost never necessary in C++. Use const or enum to define manifest constants, inline to avoid function-calling overhead, templates to specify families of functions and types, and namespaces to avoid name clashes.
  2. Don't declare a variable before you need it so that you can initialize it immediately. A declaration can occur anywhere a statement can.
  3. Don't use malloc. The new operator does the same job better, and instead of realloc(), try a vector.
  4. Try to avoid void*, pointer arithmetic, unions, and casts, and, except deep within the implementation of some function or class. In most cases, a cast is an indication of a design error. If you must use an explicit type conversion, try using one of the "new casts" for a more precise statement of what you are trying to do. [static_cast, reinterpret_cast, const_cast]
  5. Minimize the use of arrays and C-style strings. C++ standard library string and vector classes can often be used to simplify programming compared to traditional C style. In general, try not to build yourself what has already been provided by the standard library.
  6. To obey C linkage conventions, a C++ function must be declared to have C linkage.

Chapter 2: A Tour of C++

  1. Don't panic. All will become clearer in time.
  2. You don't have to know every detail of C++ to write good programs.
  3. Focus on programming techniques, not on language features.

Chapter 3: A Tour of the Standard Library

  1. Don't reinvent the wheel; use libraries.
  2. Don't believe in magic; understand what your libraries do, how they do it, and at what cost they do it.
  3. When you have a choice, prefer the standard library to other libraries.
  4. Do not think that the standard library is ideal for everything. Remember to #include the headers for the facilities you use.
  5. Remember that standard library facilities are defined in namespace std.
  6. Use string rather than char*.
  7. If in doubt, use a range-checked vector (such as Vec).
  8. Prefer Vector<T>, list<T>, and map<key,value> to T[].
  9. When adding elements to a container, use push_back() or back_inserter().
  10. Use push_back() on a vector rather than realloc() on an array.
  11. Catch common exceptions in main().

Chapter 4: Types and Declarations

  1. Keep scopes small.
  2. Don't use the same name in both a scope and an enclosing scope.
  3. Declare one name (only) per declaration.
  4. Keep common and local names short, and keep uncommon and nonlocal names longer.
  5. Avoid similar-looking names. Maintain a consistent naming style. Choose names carefully to reflect meaning rather than implementation.
  6. Use a typedef to define a meaningful name for a built-in type in cases in which the built-in type used to represent a value might change.
  7. Use typedefs to define synonyms for types; use enumerations and classes to define new types.
  8. Remember that every declaration must specify a type (there is no "implicit int".
  9. Avoid unnecessary assumptions about the numeric value of characters.
  10. Avoid unnecessary assumptions about the size of integers.
  11. Avoid unnecessary assumptions about the range of floating-point types.
  12. Prefer a plain int over a short int or a long int.
  13. Prefer a double over a float or a long double.
  14. Prefer plain char over signed char and unsigned char.
  15. Avoid making unnecessary assumptions about the sizes of objects.
  16. Avoid unsigned arithmetic.
  17. View signed to unsigned and unsigned to signed conversions with suspicion.
  18. View floating-point to integer conversions with suspicion.
  19. View conversion to a smaller type, such as int to char, with suspicion.

Chapter 5: Pointers, Arrays, and structures

  1. Avoid nontrivial pointer arithmetic.
  2. Take care not to write beyond the bounds of an array.
  3. Use 0 rather than NULL.
  4. Use vector and valarray rather than built-in(C-style) arrays.
  5. Use string rather than zero-terminated arrays of char.
  6. Minimize use of plain reference arguments.
  7. Avoid void * except in low-level code.
  8. Avoid nontrivial literals ("magic numbers") in code. Instead, define and use symbolic constants.

Chapter 6: Expressions and Statements

  1. Prefer the standard library to other libraries and to :handcrafted code".
  2. Avoid complicated expressions.
  3. If in doubt about operator precedence, parenthesize.
  4. Avoid explicit type conversion (casts).
  5. When explicit type conversion is necessary, prefer the more specific cast operators to the C-style cast.
  6. Use the T(e) notation exclusively for well-defined construction.
  7. Avoid expressions with undefined order of evaluation.
  8. Avoid goto.
  9. Avoid do-statements.
  10. Don't declare a variable until you have a value to initialize it with.
  11. Keep comments crisp.
  12. Maintain a coinsistent indentation style.
  13. Prefer defining a member operator new() to replacing the global operator new().
  14. When reading input, always consider ill-formed input.

Chapter 7: Functions

  1. Be suspicious of non-const reference arguments; if you want the function to modify its arguments, use pointers and value return instead.
  2. Use const reference arguments when you need to minimize copying of arguments.
  3. Use const extensively and consistently.
  4. Avoid macros.
  5. Avoid unspecified numbers of arguments.
  6. Don't return pointers or references to local variables.
  7. Use overloading when functions perform conceptually the same task on different types.
  8. When overloading on integers, provide enough functions to eliminate common ambiguities.
  9. When considering the use of a pointer to function, consider whether a virtual function or a template would be a better alternative.

Chapter 8: Namespaces and Exceptions

  1. Use namespace to express logical structure.
  2. Place every non-local name, except main(), in some namespace.
  3. Design a namespace so that you can conveniently use it without accidentaly gaining access to unrelated namespaces.
  4. Avoid very short names for namespaces.
  5. If necessary, use namespace aliases to abbreviate long namespace names.
  6. Avoid placing heavy notational burdens on users of your namespace.
  7. Uset the Namespace::member notation when defining namespace members.
  8. Use using namespace only for transition or within a local scope.
  9. Use exceptions to decouple the treatment of "errors" from the code dealing with the ordinary processing.
  10. Use user-defined rather than built-in types as exceptions.
  11. Don't use exceptions when local control structures are sufficient.

Chapter 9: Source Files and Programs

  1. Use header files to represent interfaces and to emphasize logical structure.
  2. #include a header in the source file that implements its functions.
  3. Don't define global entities with the same name and similar-but-different meanings in different translation units.
  4. Avoid non-inline function definitions in headers.
  5. Use #include only at global scope and in namespaces.
  6. #include only complete declarations.
  7. Use include guards.
  8. #include C headers in namespaces to avoid global names.
  9. Make headers self-contained.
  10. Distinguish between user's interfaces and implementers' interfaces.
  11. Distinguish between average users' interfaces and expert users' interfaces.
  12. Avoid nonlocal objects that require run-time initialization in code inteded for use as part of non C++ programs.

Chapter 10: Classes

  1. Represent concepts as classes.
  2. Use public data (structs) only when it really is just data and no invariant is meaningful for the data members.
  3. A concrete type is the simplest kind of class. Where applicable, prefer a concrete type over more complicated classes and over plain data structures.
  4. Make a function a member only if it needs direct access to the representation of a class.
  5. Use a namespace to make the association between a class and its helper functions explicit.
  6. Make a member function that doesn't modify the value of its objects a const member function.
  7. Make a function that needs access to the representation of a class but needn't be called for a specific object a static member function.
  8. Use a constructor to establish an invariant for a class.
  9. If a constructor acquires a resource, its class needs a destructor to release the resource.
  10. If a class has a pointer member, it needs copy operations (copy constructor and copy asignment).
  11. If a class has a reference member, it probably needs copy operations (copy constructor and copy assignment).
  12. If a class needs a copy operation or a destructor, it probably needs a constructor, a destructor, a copy assignment, and a copy constructor.
  13. Check for self-assignment in copy assignments.
  14. When writing a copy constructor, be careful to copy every element that needs to be copied (beware of default initializers).
  15. When adding a new member to a class, always check to see if there are user-defined constructors that need to be updated to initialize the member.
  16. Use enumerators when you need to define integer constants in class declarations.
  17. Avoid order dependencies when constructing global and namespace objects.
  18. Use first-time switches to minimize order dependencies.
  19. Remember that temporary objects are destroyed at the end of the full expression in which they are created.

Chapter 11: Operator Overloading

  1. Define operators primarily to mimic conventional usage.
  2. For large operands use const reference argument types.
  3. For large results, consider optimizing the returns.
  4. Prefer the default copy operations if appropriate for a class.
  5. Redefine or prohibit copying if the default is not appropriate for a type.
  6. Prefer member functions over nonmembers for operations that need access to the representation.
  7. Use namespaces to associate helper functions with "their" class.
  8. Use nonmember functions for symmetric operators.
  9. Use () for subscripting multidimensional arrays.
  10. Make constructors that take a single "size argument" explicit.
  11. For non-specialized uses, prefer the standard string to the result of your own exercises.
  12. Be cautious about introducing implicit conversions.
  13. Use member functions to express operators that require an lvalue as left-hand operand.

Chapter 12: Derived Classes

  1. Avoid type fields.
  2. Use pointers and references to avoid slicing.
  3. Use abstract classes to focus design on the provision of clean interfaces.
  4. Use abstract classes to minimize interfaces.
  5. Use abstract classes to keep implementation details out of interfaces.
  6. Use virtual functions to allow new implementations to be added without affecting user code.
  7. Use abstract classes to minimize recompilation of user code.
  8. Use abstract classes to allow alternative implementations to coexixt.
  9. A class with a virtual function should have a virtual destructor.
  10. An abstract class typically doesn't need a constructor.
  11. Keep the representations of distinct concept distinct.

Chapter 13: Templates

  1. Use templates to express algorithms that apply to too many argument types.
  2. Use templates to express containers.
  3. Provide specializations for containers of pointers to minimize code size.
  4. Always declare the general form of a template before specializations.
  5. Declare a specialization before its use.
  6. Minimize a template definition's dependence on its instantiation contexts.
  7. Define every specialization you declare.
  8. Consider if a template needs specializations for C-style strings and arrays.
  9. Parameterize with a policy object.
  10. Use specialization and overloading to provide a single interface to implementations of the same concept for different types.
  11. Provide a simple interface for simple cases and use overloading and default arguments to express less common cases.
  12. Debug concrete examples before generalizing to a template.
  13. Remember to export template definitions that need to be accessible from other translation units.
  14. Separately compile large templates and templates with nontrivial context dependencies.
  15. Use templates to express conversions but define those conversions very carefully.
  16. Where necessary, constrain template arguments using a constraint() member function.
  17. Use explicit instantiation to minimize compile time and link time.
  18. Prefer a template over derived classes when run-time efficiency is at a premium.
  19. Prefer derived clases over a template if adding new variants without recompilation is important.
  20. Prefer a template over derived classes when no common base can be defined.
  21. Prefer a template over derived classes when built-in types and structures with compatibility constraints are important.

Chapter 14: Exception Handling

  1. Use exceptions for error handling.
  2. Don't use exceptions where more local control structures will suffice.
  3. Use the "resource allocation is initialization" technique to manage resources.
  4. Not every program needs to be exception safe.
  5. Use "resource allocation is initialization" and exception handlers to maintain invariants.
  6. Minimize the use of try-blocks. Use :resource acquisition is initialization" instead of explicit handler code.
  7. Not every function needs to handle every possible error.
  8. Throw an exception to indicate failure in a constructor.
  9. Avoid throwing exceptions from copy constructors.
  10. Avoid throwing exceptions from destructors.
  11. Have main() catch and report all exceptions.
  12. Keep ordinary code and error-handling code separate.
  13. Be sure that every resource acquired in a constructor is released when throwing an exception in that constructor.
  14. Keep resource management hierarchical.
  15. Use exception-specifications for major interfaces.
  16. Beware of memory leeks caused by memory allocated by new not being released in case of an exception.
  17. Assume that every exception that can be thrown by a function will be thrown.
  18. Don't assume that every exception is derived from clkass exception.
  19. A library should not unilaterally terminate a program. Instead, throw an exception and let a caller decide.
  20. A library shouldn't produce diagnostic output aimed at end users. Instead, throw an exception and let a caller decide.
  21. Develop an error-handling strategy early in a design.

Chapter 15: Class hierarchies

  1. Use ordinary multiple inheritance to express a union of features.
  2. Use multiple inheritance to separate implementation details from an interface.
  3. Use a virtual base to represent something common to some, but not all, classes in a hierarchy.
  4. Avoid explicit type conversion (casts).
  5. Use dynamic_cast where class hierarchy navigation is inavoidable.
  6. Prefer dynamic_cast over ,i>typeid.
  7. Prefer private to protected.
  8. Don't declare data members protected.
  9. If a class defines operator delete(), it should have a virtual destructor.
  10. Don't call virtual functions during construction or destruction.
  11. Use explicit qualification for resolution of member names sparingly and preferably use it in overriding functions.

Chapter 16: Library Organization and Containers

  1. Use standard library facilities to maintain portability.
  2. Don't try to redefine standard library facilities.
  3. Don't believe that the standard library is best for everything.
  4. When building a new facility, consider whether it can be presented within the framework offered by the standard library.
  5. Remember that standard library facilities are defined in namespace std.
  6. Declare standard library facilities by including its header, not by explicit declaration.
  7. Take advantage of late abstraction.
  8. Avoid fat interfaces.
  9. Prefer algorithms with reverse iterators over explicit loops dealing with reverse order.
  10. Use base() to extract and iterator from a reverse_iterator.
  11. Pass containers by reference.
  12. Use iterator types, such as list<char>::iterator, rather than pointers to refer to elements of a container.
  13. Use const iterators where you don't need to modify the elements of a container.
  14. Use at(), directly or indirectly, if you want range checking.
  15. Use push_back() or resize on a container rather than realloc on an array.
  16. Don't use iterators into a resized vector.
  17. Use reserve() to avoid invalidating iterators.
  18. When necessary, use reserve() to make performance predictable.

Chapter 17: Standard Containers

  1. By default, use a vector when you need a container.
  2. Know the cost (complexity, Big-O measure) of every operation you use frequently.
  3. The interface, implementation, and representation of a container are distinct concepts. Don't confuse them.
  4. You can sort and search according to a variety of criteria.
  5. Do not use a C-style string as a key unless you supply a suitable comparison criterion.
  6. You can define a comparison criteria so that equivalent, yet different, key values map to the same key.
  7. Prefer operations on the end of a sequence (back-operations) when inserting and deleting elements.
  8. Use list when you need to do many insertions and deletions from the front or the middle of a container.
  9. Use map or multimap when you primarily access elements by key.
  10. Use the minimal set of operations to gain maximum flexibility.
  11. Prefer a map to a hash_map if the elements need to be in order.
  12. Prefer a hash_map to a map when speed of lookup is essential.
  13. Prefer a hash_map to a map if no less-than operation can be defined for the elements.
  14. use find() when you need to check if a key is in an associative container.
  15. Use multimap when several values need to be kept for a single key.
  16. Use set or multiset when the key itself is the only value you need to keep.

Chapter 18: Algorithms and Function Objects

  1. Prefer algorithms to loops.
  2. When writing a loop, consider whether it could be expressed as a general algorithm.
  3. Regularly review the set of algorithms to see if a new application has become obvious.
  4. Be sure that a pair of iterator arguments really do specify a sequence.
  5. Design so that the most frequently-used operations are simple and safe.
  6. Express tests in a form that allows them to be used as predicates.
  7. Remember that predicates are functions and objects, not types.
  8. You can use binders to make unary predicates out of binary predicates.
  9. Use mem_fun() and mem_fun_ref() to apply algorithms on containers.
  10. Use ptr_fun() when you need to bind an argument of a function.
  11. Remember that strcmp() differs from == by returning 0 to indicate "equal".
  12. Use for_each() and transform() only when there is no more-specific algorithm for a task.
  13. Use predicates to apply algorithms using a variety of comparison and equality criteria.
  14. Use predicates and other function objects so as to use standard algorithms with a wider range of meanings.
  15. The default == and < on pointers are rarely adequate for standard algorithms.
  16. Algorithms do not directly add or subtract elements from their argument sequences.
  17. Be sure that the less-than and equality predicates used on a sequence match.
  18. Sometimes, sorted sequences can be used to increase efficiency and elegance.
  19. Use qsort() and bsearch() for compatibility only.

Chapter 19: Iterators and Allocators

  1. When writing an algorithm, decide which kind of iterator is needed to provide acceptable efficiency and express the algorithm [using] the operators supported by that kind of iterator (only).
  2. Use overloading to provide more-efficient implementations of an algorithm when given as arguments iterators that offer more than minimal support for the algorithm.
  3. Use iterator_traits to express suitable algorithms for different iterator categories.
  4. Remember to use ++ between accesses of istream_iterators and ostream_iterators.
  5. Use inserters to avoid container overflow.
  6. Use extra checking during debugging and remove checking later only where necessary.
  7. Prefer ++p to p++.
  8. Use uninitialized memory to improve the performance of algorithms that require temporary data structures.
  9. Use temporary buffers to improve the performance of algorithms that require temporary data structures.
  10. Think twice before writing your own allocator.
  11. Avoid malloc(), free(), realloc(), etc.
  12. You can simulate a typedef of a template by the technique used for rebind.

Chapter 20: Strings

  1. Prefer string operations to C-style string functions.
  2. Use strings as variables and members, rather than as base classes.
  3. You can pass strings as value arguments and return them by value to let the system take care of memory management.
  4. Use subscripting rather than iterators when you want range checking.
  5. Use iterators rather than subscripting when you want to optimize speed.
  6. Directly or indirectly, use substr() to read substrings and replace() to write substrings.
  7. Use the find() operations to localize values in a string (rather than writing an explicit loop).
  8. Append to a string when you ned to add characters efficiently.
  9. Use strings as targets of non-time-critical character input.
  10. Use string::npos to indicate "the rest of the string".
  11. If necessary, implement heavily used strings using low-level operations (rather than using low-level data structures everywhere).
  12. If you use strings, catch range_error and out_of_range somewhere.
  13. Be careful not to pass a char* with the value 0 to a string function.
  14. Use c_str() rather to produce a C-style string representation of a string only when you have to.
  15. Use isalpha(), isdigit(), etc. when you need to know the classification of a character rather than writing your own tests on character values.

Chapter 21: Streams

  1. Define << and >> for user-defined types with values that have meaningful textural representations.
  2. Use parentheses when printing expressions containing operators of low precedence.
  3. You don't need to modify istream or ostream to add new << or >> operators.
  4. You can define a function so that it behaves as a virtual function based on its second (or subsequent) argument.
  5. Use lower-level input functions such as get() and read() only where run-time efficiency is at a premium.
  6. Use lower-level input functions such as get() and read() primarily in the implementation of higher-level input functions.
  7. Be careful with the termination criteria when using get(), getline(), and read().
  8. Prefer manipulators to state flags for controlling I/O.
  9. Use exceptions to catch rare I/O errors.
  10. Tie streams used for interactive I/O.
  11. Use sentries to concentrate entry and exit code for many functions in one place.
  12. Don't use parentheses after a no-argument manipulator.
  13. Remember to include #include <iomanip> when using standard manipulators.
  14. You can achieve the effect (and efficiency) of a ternary operator by defining a simple function object.
  15. Remember that width specifications apply to the following I/O operation only.
  16. Remember that precision specifications apply to all following floating-point output operations.
  17. Use string streams for in-memory formatting.
  18. You can specify a mode for a file stream.
  19. Distinguish sharply betwen formatting (iostreams) and buffering (streambufs) when extending the I/O system.
  20. Implement nonstandard ways of transmitting values as stream buffers.
  21. Implement nonstandard ways of formatting values as stream operations.
  22. You can isolate and encapsulate calls of user-defined code by using a pair of functions.
  23. You can use in_avail() to determine whether an input operation will block before reading.
  24. Distinguish between simple operations that need to be efficient and operations that implement policy (make the former inline and the latter virtual).
  25. Use locale to localize "cultural differences".
  26. Use sync_with_stdio() if you mis C-style and C++-style I/O.
  27. Beware of type errors in C-style I/O.

Chapter 22: Numerics

  1. Numerical problems are often subtle. If you are not 100% certain about the mathematical aspects of a numerical problem, either take expert advice or experiment.
  2. Use numeric_limits to determine properties of built-in types.
  3. Specialize numeric_limits for user-defined scalar types.
  4. Use valarray for numeric computation when run-time efficiency is more important than flexibility with respect to operations and element types.
  5. Express operations on part of an array in terms of slices rather than loops.
  6. Use compositors to gain efficiency through elimination of temporaries and better algorithms.
  7. Use std::complex for complex arithmetic.
  8. You can convert old code that uses a complex class to use the std::complex template by using a typedef.
  9. Consider accumulate(), inner_product(), partial_sum(), and adjacent_difference() before you write a loop to compute a value from a list.
  10. Prefer a random-number class for a particular distribution over direct use of rand()
  11. Be careful that your random numbers are sufficiently random.

Chapter 23: Development and Design

  1. Know what you are trying to achieve.
  2. Keep in mind that software development is a human activity.
  3. Proof by analogy is fraud.
  4. Have specific and tangible aims.
  5. Don't try technological fixes for sociological problems.
  6. Consider the longer term in design and in the treatment of people.
  7. There is no lower limit to the size of programs for which it is sensible to design before starting to code.
  8. Design processes to encourage feedback.
  9. Don't confuse activity for progress.
  10. Don't generalize beyond what is needed, what you have direct experience with, and what can be tested.
  11. Represent concepts as classes.
  12. There are properties of a system that should not be represented as a class.
  13. Represent hierarchical relationships between concepts as class hierarchies.
  14. Actively search for commonality in the concepts of the application and implementation and represent the resulting more general concepts as base classes.
  15. Classifications in other domains are not necessarily useful classifications in an inheritance model for an application.
  16. Design class hierarchies based on behavior and invariants.
  17. Consider use cases.
  18. Consider using CRC cards.
  19. Use existing systems as models, as inspiration, and as starting points.
  20. Beware of viewgraph engineering.
  21. Throw a prototype away before it becomes a burden.
  22. Design for change, focusing on flexibility, extensibility, portability, and reuse.
  23. Focus on component design.
  24. Use classes to represent concepts.
  25. Design for stability in the face of change.
  26. Make designs stable by making heavily-used interfaces minimal, general, and abstract.
  27. Keep it small. Don't add features "just in case".
  28. Always consider alternative representations for a class. If no alternative representation is plausible, the class is probably not representing a clean concept.
  29. Repeatedly review and refine both the design and the implementation.
  30. Use the best tools available for testing and for analyzing the problem, the design, and the implementation.
  31. Experiment, analyze, and test as early as possible and as often as possible.
  32. Don't forget about efficiency.
  33. Keep the level of formality appropriate to the scale of the project.
  34. Make sure that somebody is in charge of the overall design.
  35. Document, market, and support reusable components.
  36. Document aims and principles as well as details.
  37. Provide tutorials for new developers as part of the documentation.
  38. Reward and encourage reuse of designs, libraries, and classes.

Chapter 24: Design and Programming

  1. Evolve use towards data abstraction and object-oriented programming.
  2. Use C++ features and techniques as needed (only).
  3. Match design and programming style.
  4. Use classes/concepts as primary focus for design rather than functions/processing.
  5. Use classes to represent concepts.
  6. Use inheritance to represent hierarchical relationshipd between concepts (only).
  7. Express strong guaranties about interfaces in terms of application-level static types.
  8. Use program generators and direct-manipulation tools to ease well-defined tasks.
  9. Avoid program generators and direct manipulation tools that do not interface cleanly with a general-purpose programming language.
  10. Keep distinct levels of abstraction distinct.
  11. Focus on component design.
  12. Make sure that a virtual function has a well-defined meaning and that every overriding function implements a version of that desired behavior.
  13. Use public inheritance to represent is-a relationships.
  14. Use membership to represent has-a relationships.
  15. Prefer membership to pointers for expressing simple containment.
  16. Make sure that the uses dependencies are understood, non-cyclic wherever possible, and minimal.
  17. Define invariants for all classes.
  18. Explicitly express preconditions, postconditions, and other assertions as assertions (possibly using Assert).
  19. Define interfaces to reveal the minimal amount of information needed.
  20. Minimize an interface's dependencies on other interfaces.
  21. Keep interfaces strongly typed.
  22. Express interfaces in terms of application level types.
  23. Express an interface so that a request could be transmitted to a remote server.
  24. Avoid fat interfaces.
  25. Use private data and member functions wherever possible.
  26. Use the public/protected distinction to distinguish between the needs of the designers of derived classes and general users.
  27. Use templates for generic programming.
  28. Use templates to parameterize an algorithm by a policy.
  29. Use templates where compile-time type resolution is needed.
  30. Use class hierarchies where run-time type resolution is needed.

Chapter 25: Roles of Classes

  1. Make conscious decisions about how a class is to be used (both as a designer and as a user).
  2. Be aware of the tradeoffs involved among the different kinds of classes.
  3. Use concrete types to represent simple independent concepts.
  4. Use concrete types to represent concepts where close-to-optimal efficiency is essential.
  5. Don't derive from a concrete class.
  6. Use abstract classes to represent interfaces where the representation of objects might change.
  7. Use abstract classes to represent interfaces where different representations of objects may need to coexist.
  8. Use abstract classes to represent new interfaces to existing classses.
  9. Use node classes where similar classes share significant implementation details.
  10. Use node classes to incrementally augment an implementation.
  11. Use Run-time Type Identification to obtain new interfaces for an object.
  12. Use classes to represent actions with associated state.
  13. Use classes to represent actions that need to be stored, transmitted, or delayed.
  14. Use interface classes to adapt a class for a new kind of use (without modifying the class).
  15. Use interface classes to add checking.
  16. Use handles to avoid direct use of pointers and references.
  17. Use handles to manage shared representations.
  18. Use an application framework where an application domain allows for control structure to be predefined.