- Getting Started
- Inheritance and Delegation
- Public Access to Data
- More OOP Concerns
- A Flexible Interface
- Crafting Parameter Lists
- Other Concerns
- Summary
Inheritance and Delegation
On the other hand, if your class does fit into an inheritance hierarchy: Is there some existing class or classes that it makes sense to inherit from? Again, don't reinvent the wheel. Do you want to make an EncryptedString class? It would be natural to inherit from a String class if you have one.
Don't attempt to inherit from the container classes in the STL. They are not designed to be used in that way, as they have no virtual functions.
For that matter, sometimes a little informal delegation is in order. Rather than inheriting from a class ("is-a" relationship), you can embed an object of that class ("has-a" relationship). This can be useful if you don't want to expose all the functionality of the pre-existing class, but want to control access to its features through your own interface. For example, if you were creating a stack class from scratch, you might consider embedding a Vector object within the class, accessible only from your member functions. But you would not want to make your stack a descendant of Vector; you would end up exposing functionality that made no sense (for example, accessing an item in the middle of the collection) or else you would go to extra effort to mask out that functionality.
Looking the other way down the hierarchy: Would it ever make sense to inherit from this class? If so, you should consider whether some of the functions should be virtual, so that they can be overridden in the child classes. The child class always has features that distinguish it from the parent (that is, specialize it) and they will frequently correspond directly to the parent's features so that the functions will be named the same.
class Automobile { virtual void clean_exterior() { clean_body(); clean_glass(); clean_wheels(); } // ... } class Convertible : public Automobile { virtual void clean_exterior() { Automobile::clean_exterior(); clean_ragtop(); } // ... }
Note in this case that the child method calls the parent method. This is good practice because it avoids the duplication of code and increases maintainability.
Sometimes, methods should be made pure virtual functions, so that they must be overridden in the descendants. Finally, consider the possibility of an abstract base class: a parent class in which all the functions are pure virtual. These are cases in which the children's behavior may vary widely from each other, and there may be little commonality across the hierarchy.
class Organism // An abstract base class { virtual eat() = 0; virtual reproduce() = 0; // ... }
Remember that an abstract base class should in general not contain any data members. In addition, it should have a pure virtual destructor that is not only declared but defined.