I'd object to your example: your example seems to me to be closer to that of instance :: class than subclass :: superclass. PrinterDriver defines a contract; each of HPDriver, CanonDriver etc. will need to fulfill the contract. But I don't see them usefully adding behaviour. The OS would have to already know about HPDriver in order to use its extra functionality - then what's the point in using inheritance at all?
In a lot of OO languages instances rarely have different behaviour to each other.
You are also forgetting that it's possible to have more than one printer using the same driver (i.e. multiple instances of a class of printers). This is not uncommon when you consider network printers.
> The OS would have to already know about HPDriver in order to use its extra functionality
And that isn't true of any other instance in which inheritance is used?
A common pattern is a superclass with "abstract" methods that subclasses then implement. So the `sendCommand(cmd)` function is implemented in HPDriver and CanonDriver and higher level methods in PrinterDriver can use that piece even though PrinterDriver itself has no implementation of that method.
I don't understand how a driver implementation is an instance. I can imagine the HPDriver class having completely different code than the CanonDriver class.
For a realistic version of this example, consider JDBC driver implementations.
Perhaps they are scanner & printer drivers, the implementation exposes a ScannerDriver interface and a PrinterDriver interfaces. They subclass a DeviceDriver that implements the low-level I/O. There are other generic and vendor-specific interfaces that could be used here, as well as perhaps some kind of more specific class on top of DeviceDriver like PCLDriver or PostScriptDriver.
class HPDriver extends DeviceDriver implements ScannerDriver, PrinterDriver
Different printer models could have different features (color/B&W, selecting output tray, “print” an outgoing fax, etc.), and you could make each PrinterDriver subclass responsible for generating the appropriate UI code for frobbing those features.