From "Code Complete 2", Abstraction says "You are allowed to look at an object at a high level of detail". Encapsulation says "Furthermore, you are not allowed to look at the object at any other level of detail". I don't think there are other way can elaborate these two concepts to such a simple and clear level.
Also from "Code Complete 2", There are two secrets about "Information hiding":
1. Hiding complexity so that your brain doesn't have to deal with it unless you specifically concerned with it
2. Hiding sources of change so that when change occurs, the effects are localized
Actually the two points defines two sides of dealing with the essential problem of software engineering: managing the complexity. And different methodologies and philosophies are developed cater for this essential problem, including OOX (where X can be D, or P), and AOX (Aspect Oriented X).
Purely Object Oriented approach save you from concerning about how a specific functionality is implemented, i.e. you just need to know what function you need to call, you don't need to know how that function is implemented.
Aspect Oriented approach moves one step further from there, you even don't need to think about what function you need to call if that function is beyond your current concern, e.g. you don't need to think about logging, error handling or authentication while you are coding/designing for Account Transfer functionality. Instead your brain deals with only one aspect of the program at a time in AOP, and at a super time your brain will become a super brain that think about how all aspect will be weaved together, of course, the super brain will not dealing with how each aspect works, it just concern about the interaction of aspects.
Steven define "Inheritance" as defining similarities and differences among objects (like full-time employee and part-time employee). That is correct. But there is a problem: how you can clearly define the similarities and differences among object. If you really keep you updated about software design and implementing technical development, you should be aware that "Inheritance" is much less a referred good approach now than, say 10 years ago. I think the reason is, while "Inheritance" provide one approach for concept modeling and method reusing, it suffers from an ugly problem with software structure - high coupling. There are many good discussions about this topic, please refer to http://www.travisswicegood.com/index.php/2007/10/11/why_class_inheritance_sucks for detail.
One interesting essay about Inheritance is that "The difference between is-a and has-a relationships is well known and a fundamental part of OOAD, but what is less well known is that almost every is-a relationship would be better off re-articulated as a has-a relationship." So the gist is to favor composition to Inheritance. Well, I would like to say it is a good approach, and I follow that in my systems. What I want to say is there is one concept hiding from curtain: Interface publication. Whenever you are trying to use composition paradigm, you are actually defines an interface which is implemented by both the composed class and the composition blocks. So the problem becomes to what level you want your interface be granulated. The more fine-grained your levels are, the more elaborated your system are, and the more easier to re factory the system if needed. On the other side, the more coarse-grained, the less complexity your system is and in turn the transparency level is improved. Just as Steven says, "the challenge of design is to creating a good set of tradeoffs from competing objectives.