When I want to give an example of how inheritance works, I always point to C#'s Stream
class.
The Stream
class is an abstraction of the idea of a data stream from which bytes can be taken or to which bytes can be stored. Its child classes include FileStream
which represents the data of a file, MemoryStream
which represents data in memory (RAM), BufferedStream
which is an adaptor to provide an extra layer of data buffering, and CryptoStream
which represents a layer of encryption.
It's a very abstract example, but it's a real world example that highlights how different implementations of the same interface can be incredibly useful. It demonstrates the use of virtual functions, abstraction, the dependency inversion principle and the liskov substitution principle.
Any Stream
can be wrapped in a StreamReader
, StreamWriter
, BinaryReader
or BinaryWriter
to handle the ability to read/write data more complex than bytes. These are also good examples of the decorator pattern being used 'in the wild'.
(StreamReader
and StreamWriter
in turn inherit TextReader
and TextWriter
, which are themselves another good example.)