Before starting this chapter, let me phrase this advice:
Always prefer composition over inheritance when applicable. Use inheritance when you have to.
Design your system through policies or contracts and let your implementation details to obey them. This principle works well with other idioms and design principles.
-
Derived class is customization of a base class. Base class should impose pre/post conditions and child classes should always respect. Base class is the contract.
-
Consider using Nonvirtual Interface (NVI) pattern by making virtual functions nonpublic and public functions nonvirtual.
- Another way of seperation of interface and implementation
- nonvirtual public methods are representing the interfaces.
- virtual protected/private methods provide customization point (implementation detail)
- Base class controls the policy through checking pre/post conditions. Instrumentation can be inserted at this level.
- Supports single reponsibility principle. Nonvirtual public function does not have to specify interface and implementation together.
-
Do not inherit from classes which are not designed to be a base class i.e.
std::string. Prefer composition:- public nonvirtual destructor causes undefined behavior by deleting pointers to string that points to der_string.
- std::string is not protected against slicing
-
Prefer
protectedmethods rather thanprotectedfields: It is as bad aspublicsince it is giving access to its internals to its child class. -
Do not call virtual functions from in
constructorsanddestructors. -
Make base class destructors
public virtualorprotected non-virtual. -
Prefer
clone()approach to avoid slicing. -
Never redefine inherited non-virtual functions in the child class.
Dependency Inversion Principle: Modules and implementation details should depend on abstractions. Provide Abstract Interface: It is a class definition with
- pure virtual function declerations
- No member data - no state (preffered)
- No implementation
- virtual destructor if
polymorpohic deletionto be supported.
- Do not redeclare default arguments of virtual functions when overriding.
Privatemethods can also be virtual and be overriden by child classes.
There three inheritance types public, protected, private , multiple and virtual. These do not compete with each other. They represent different idioms to model a specific logic.
Represents is a relationship.
Represents implemented in terms of relationship such as composition.
Base class destructor should be virtual.
Control copy & move behavior through base classes.
If copy is disabled, use clone() approach to copy.