Note: this has been completely rewritten from my earlier example
Think about power sockets. In any given nation, the high-level policy is that power sockets are always the same. It doesn't matter where you get you electricity from (coal, gas, nuclear), the sockets on the wall should always put out the same amount of power, through the same set of connectors.
Now you can plug any device into that socket, because they all have a common interface, the "plug". The high-level policy never has to dictate any part of that implementation detail. Just plug something in and it goes.
Now if you have a device that doesn't want AC power -- maybe it runs on a 7V DC circuit -- you can still use that high-level policy, you just need some kind of adapter between the power supply and the device. And, because everyone has the same high-level policy, the manufacturer can build that into the implementation, without any change to the high-level policy. The person connecting the implementation to the policy (you, plugging your laptop in) doesn't really need to understand either.
Further, if the manufacturer wants to sell the same device in another country, all they have to do is develop a different adapter. So the same implementation can work with multiple policies while the same policy can run multiple implementations.
This is a perfect example of dependency inversion.
But here's the interesting bit: Go back to what I first said. "It doesn't matter where you get you electricity from." This is also an implementation detail. The high-level policy is still that all power sockets are the same shape and emit the same type of power. The low-level implementation details are both where the electricity comes from and what it runs.
In programming terms, that means the high-level policy is the interface (Where a language supports it. Another form of DI is duck-typing.) that an API provides and the application consumes, and the low-level implementation details are both the application consuming it and the API itself, neither of which need to understand each other.
Adapters may be used to fit the same implementation into different policies.
Your understanding of the concept is very accurate.
Pointing out exceptions, special cases or philosophical minutiae right now would be diverting you from your present clarity of concept.
I would suggest, though, you use UML symbols:
![enter image description here](https://i.stack.imgur.com/ekYdF.png)
- Open arrow : uses
- Closed arrow: inherits or implements
- << name in brackets >> : interface or abstract class
Best Answer
What he's saying here is that you should avoid a scenario where a base class takes a dependency to meet the need of a descendant. Let's look at the case of a Switch and its descendant the TimedSwitch. The TimedSwitch is a Switch that resets itself after a certain amount of time. We have the TimedObject class already so it would make sense for TimedSwitch to derive from it...however TimedSwitch already derives from Switch. So in order to meet the needs of the TimedSwitch, Switch will inherit from TimedObject even though it doesn't need that functionality itself.
The Switch (abstraction) is dependent on the details of TimedSwitch. To fix this violation of the DIP, we have TimedSwitch implement ITimedObject and delegate to a contained TimedObject class (prefer composition over inheritance).
Another more generic example is the layered approach. The higher level layers are abstractions and in most cases they depend on the details. DIP says that instead, the lower layers should conform to an interface which they both take dependency on. Thus the dependency is inverted from Higher Layer depending on lower layer to both layers depending on an interface.