Creating and Implementing an Encapsulated Class
The dictionary defines encapsulation as “to encase in or as if in a capsule” and that is exactly the approach that C++ uses. An object is a “capsule” and the information and processing algorithms that it implements are hidden from the user. All that the users see is the functional-level interface that allows them to use the class to do the job they need done. By placing the data within the interface, rather than allowing the user direct access to it, the data is protected from invalid values, wrongful changes, or improper coercion to new data types. Listing 1-1 presents the string coding class, an encapsulated method of encryption. The benefit of encapsulation is, in effect, that it cuts to the chase: The programmer utilizing our string coding class knows nothing about the algorithm used to encrypt strings — and doesn’t really need to know what data was used to encrypt the string in the first place. Okay, but why do it? Well, you have three good reasons to “hide” the implementtat ion of an algorithm from its user:
Making Updates to an Encapsulated Class
One of the benefits of encapsulation is that it makes updating your hidden data simple and convenient. With encapsulation, you can easily replace the underlying encryption algorithm in Listing 1-1 with an alternative if one is found to work better. In our original algorithm, we did an “exclusive logical or” to convert a character to another character. In the following example, suppose that we want to use a different method for encrypting strings. For simplicity, suppose that this new algorithm encrypts strings simply by changing each character in the input string to the next letter position in the alphabet: An a becomes a b, a c becomes a d, and so on. Obviously, our decryption algorithm would have to do the exact opposite, subtracting one letter position from the input string to return a valid output string. We could then modify the Encode method in Listing 1-1 to reflect this change. The following steps show how:
You might think that this approach would have an impact on the developers who were using our class. In fact, we can make these changes in our class (check out the resulting program on this book’s companion Web site as ch1_1a.cpp) and leave the remainder of the application alone. The developers don’t have to worry about it. When we compile and run this application, we get the following output:
Creating a Mailing-List Application
This concept is just a little bit abstract (pardon the pun), so here’s a concrete example to show you how abstraction really works: Assume you want to implement a mailing list for your company. This mailing list consists of objects (called mailing-list entries) that represent each of the people you’re trying to reach. Suppose, however, that you have to load the data from one of two sources: from a file containing all the names, or directly from the user’s command line. A look at the overall “flow” of this application reveals that the two sides of this system have a lot in common:
To handle input from a file, we need some place to store the names, addresses, cities, states, and zip codes from a file. To handle input from the command line, we need to be able to load that exact same data from the command line and store it in the same place. Then we need the capability to print those mailing-list items or merge them into another document. After the input is stored in memory, of course, we don’t really care how it got there; we care only how we can access the data in the objects. The two different paths, file-based and command-line-based, share the same basic information; rather than implement the information twice, we can abstract it into a container for the mailing-list data.