According to Bjarne Stroustrup, author of the C++ programming language, for a language to call itself object-oriented, it must support three concepts: objects, classes, and inheritance. However, object-oriented languages have come to be more commonly thought of as those languages built on the tripod of encapsulation, inheritance, and polymorphism. The reason for this shift in philosophy is that over the years we've come to realize that encapsulation and polymorphism are just as integral to building object-oriented systems as class and inheritance.
Encapsulation
As I mentioned earlier, encapsulation, sometimes called information hiding, is the ability to hide the internals of an object from its users and to provide an interface to only those members that you want the client to be able to directly manipulate. However, I also spoke of abstraction in the same context, so in this section, I'll clear up any confusion regarding these two similar concepts. Encapsulation provides the boundary between a class's external interface—that is, the public members visible to the class's users—and its internal implementation details. The advantage of encapsulation for the class developer is that he can expose the members of a class that will remain static, or unchanged, while hiding the more dynamic and volatile class internals. As you saw earlier in this chapter, encapsulation is achieved in C# by virtue of assigning an access modifier—public, private, or protected—to each class member.
Designing Abstractions
An abstraction refers to how a given problem is represented in the program space. Programming languages themselves provide abstractions. Think about it like this: When was the last time you had to worry about the CPU's registers and stack? Even if you initially learned how to program in assembler, I'll bet it's been a long time since you had to worry about such low-level, machine specific details. The reason