FAQ 8.12 Is code reuse the main purpose of inheritance?

graphics/new_icon.gif

The main purpose of inheritance is to express an externally meaningful relationship that describes the behavior of two entities within the problem domain. This relationship is called the is-substitutable-for relationship, although sometimes the less accurate terms is-a or kind-of are used instead. The critical insight here is that inheritance springs out of the reality of the problem domain, not out of a technical goal within the solution domain. The most important code reuse that comes from (proper) inheritance is the reuse in large systems of existing code that trusts the new derived class to be substitutable for the base class. Reusing a snippet of code from another class can be thought of as low-level reuse.

Inheritance can result in low-level code reuse as a side effect, but low-level code reuse can also be gained from composition, sometimes more appropriately than through inheritance. Trying to achieve low-level code reuse via inheritance often results in improper inheritance. For example, deriving Stack from List is an attempt to achieve code reuse via inheritance, and it results in improper inheritance.

As suggested, composition is probably a better technique for this situation. In the following example, a Stack object is a composite built from a List object. Thus, class Stack is reusing the code from class List via composition (some or all of these member functions may be virtual; these classes use integers but real stacks and lists would be generic via templates; see FAQ 25-01).

 class Empty { }; class BadPosition { }; class List { public:   void     prepend(int item) throw();   void     append(int item) throw();   int      removeFirst() throw(Empty);   int      removeLast() throw(Empty);   void     insertAtPosition(int item, unsigned position)            throw(BadPosition);   int      removeAtPosition(unsigned position)            throw(BadPosition,Empty);   int&     operator[] (unsigned index)            throw(BadPosition,Empty);   int      operator[] (unsigned index) const            throw(BadPosition,Empty);   unsigned size() const throw();   void     setSize(unsigned newSize) throw();   unsigned countMatches(int itemToMatch) const throw();   unsigned findPositionOfMatch(int item) const throw(); protected:   // Implementation intentionally omitted }; class Stack { public:   void     push(int x)  throw();   int      pop()        throw(Empty);   int      top()  const throw(Empty);   unsigned size() const throw(); protected:   List list_; }; void Stack::push(int x) throw() { list_.append(x); } int Stack::pop() throw(Empty) { return list_.removeLast(); } int Stack::top() const throw(Empty) { return list_[list_.size()-1]; } unsigned Stack::size() const throw() { return list_.size(); } 

Here is the UML notation for composition: In the following example, a Stack object is a composite built from a List object.

graphics/08fig01.gif



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net