Inheritance has two main functions: 1) to support substitution of any one of a set of derived class instances, depending on the application context, and 2) to provide in one place code and resources that are shared across all derived instances.
Any base class guarantees that code which uses a reference to the base will compile and operate with a reference to any class that derives from the base. It is important that you design the hierarchy so clients don't need to know the implementation details that distinguish each subtype. This substitutability is the most powerful aspect of inheritance.
A base class that provides non-virtual member functions intends to provide exactly that code to each derived instance without need to define the common operations in more than one place, e.g., just in the base. Similarly, if it declares a reference of some type, it intends to provide copies of the reference to each derived instance if initialized in the base, or, if not initialized, it intends to share that type among all derived objects.
You find three kinds of class structures within inheritance hierarchies:
Any abstract functions in its base must be defined by a concrete derived class. Otherwise the inherited function remains abstract and the derived class is also abstract.
Think of public inheritance as an "is-a" relationship between derived and base classes.