CHAPTER 14

Introduction to
Object-Oriented
Programming

Chapter Objectives

By the end of the chapter, readers will be able to:

images  Define what is meant by a programming paradigm.

images  Explain the overall characteristics associated with object-oriented programming (OOP).

images  Identify some of the major components of OOP as well as its major advantages and disadvantages.

images  Discuss the characteristics of an object.

images  Explain the term “encapsulation.”

images  Define “information hiding” and discuss its importance.

images  Distinguish between the interface and implementation of a class.

images  Define “inheritance” and discuss its importance.

images  Explain the “has a” and “is a” relationships.

images  Briefly discuss the concept of polymorphism.

images  Discuss the concept of generic programming.

images  Identify the attributes and methods associated with real-world objects.

images  Use the string class.

images  Model a program using UML class diagrams.

Introduction

In Chapter 2, we discussed the procedural programming paradigm, which is one of the three common paradigms. The other two paradigms are functional and object-oriented. So far throughout this text we have focused on programming using the procedural paradigm. It is our philosophy that the fundamental skills and techniques used in procedural programming are just as important in object-oriented programming (OOP). It was our intent to present problem-solving skills, algorithm development, and the fundamental programming concepts common to most programming languages early in the text. Having now acquired these basic tools and fundamental techniques, you will hopefully find the transition into OOP not only exciting but also relatively painless.

It will soon be time to use these skills in writing object-oriented programs. However, before starting to develop these programs, we will use this chapter to explore the underlying concepts of and philosophy behind this paradigm.

As we begin to make our transition into this new model of programming, remember that at the center of the object-oriented paradigm is the word “object.” At first glance, it may not be intuitively obvious what is meant by an object. However, if you look around, everything you see is an object. A textbook, a computer, a car, and even people can be thought of as objects. Many of these objects consist of other objects if you look a little closer. For example, even though a car is an object itself, it is made up of many other objects, such as tires, an engine, and seats. One of the strengths of OOP is that it allows us to easily model, or represent, these real-world entities in a way that makes it simpler to develop, maintain, and expand complex programs.

During previous sections of the text we discussed how C++ is, in many ways, a “better C.” Now we will begin to introduce some of the powerful concepts included within C++—mainly classes and inheritance.

14.1 History of Object-Oriented Programming

Programmers have long recognized the power and usefulness of object-oriented programming. Most early languages, however, mainly fell into the realm of procedural languages. Some of the earliest languages that added functionality directly related to enhancing the object-oriented experience are Simula 67, Smalltalk, Ada, and C++.

In the 1990s, much to the credit of C++, object-oriented programming became the predominant programming paradigm. Bjarne Stroustrup, working out of Bell labs, designed C++ to be the next incremental step in the life of the C programming language. The “++”, or increment operator, designates that C was raised to the next level to create C++.

Today, many of the more popular languages—such as C# (pronounced C Sharp), Java, and VB. NET —are object oriented. Even scripting languages like JavaScript, Python, and Ruby are object oriented.

14.2 Key Concepts of Object-Oriented Programming

Although there aren't any hard and fast rules regarding the features necessary to be able to classify a language as object oriented, there are some common aspects that most OOP languages include. The following sections discuss these language features and how they pertain to object-oriented programming.

14.2.1 Encapsulation

Encapsulation refers to the ability to enclose the data, or the attributes that describe the object, and the functions that manipulate the data into one container. Collectively these encapsulated components are called a class.

As previously noted, the object is at the center of the OOP paradigm. Within programming, objects are usually nouns and are examples of UDTs, characterized by a number of unique elements, including the following:

1.  Attributes or properties: These are the data members that make the individual object unique. If we assume a type called Dog, then an object of this type could have attributes including name, breed, and gender.

2.  State: This is a description of the data within the object. Assuming we have an object of type Dog, we could assume the dog's name is Webster, his breed is golden retriever, and his gender is male.

3.  Behaviors: These describe the activities or functions the object can do and how it can be used. Our dog Webster, for example, could perform such activities as barking, sitting, and fetching.

Just as the individual variables contained within a structure are referred to as data members, so are the variables contained within a class. Data members may also be referred to as attributes, or properties. The functions that are encapsulated within a class are generally called member functions or methods. In C++, it is these member functions that provide us a way to manipulate and access the attributes of the class. Taken collectively, a class can be thought of as an abstract entity that is composed of its individual attributes or properties and the things it can do—its behaviors or methods.

Like a structure, a class is just the placeholder for the data and doesn't have any memory allocated until a variable is declared from the class. This process is referred to as instantiation, and the resulting variable is called an object. A class is very similar to an automobile, a generic category that doesn't have any physical entities or state. The instantiation of a Ford Mustang, with its specific make, model, color, and unique VIN number, would be an example of an object.

To enforce the idea of encapsulation, the data members in a class are often hidden from functions outside of the class. This process of concealing the data members is also called information hiding. Information hiding ensures that only the class's methods can change the state of its data members.

Encapsulation also enables an object to stand on its own. Since all of the data and the functions that manipulate the data are tightly bound together, all the user of the class needs to do is call the appropriate methods to manipulate the object.

14.2.2 Interface Versus Implementation

The methods of a class provide the interface through which the functions outside the class manipulate the actual data contained within the object. This interface is all the user needs to know in order to be able to effectively use the class. How the class method or function is actually implemented is usually hidden from the user of the class. This process is often language dependent but is called implementation hiding.

For example, when you go out and start your car, you turn on the ignition key, which sends the Start message, and the car starts (hopefully). You may or may not understand all of the processes this simple action initiates, and you really don't need to. You don't have to understand what is taking place under the hood to be able to start your car. The action of turning the key is all you need to know. In other words, turning the key is the interface to the starting process; the implementation details can remain a mystery.

As we continue to move into the area of OOP, you will have to begin to change your way of thinking in relation to the term “user.” In all of your previous programs, the user referred to the person who ends up using your program. Now, in many cases, the user will refer to the programmer using the class that you have created. We have found that this change in thinking is very difficult for beginning programmers.

14.2.3 Inheritance

Another extremely important feature associated with object-oriented languages is the ability to take an existing class and extend its functionality to form another class. This process is called inheritance. The new class not only has access to the functionality of the parent but can add new attributes and methods as well. This process is key in making your code more reusable.

To continue with our automobile example, we could create a base class that contains the common features of all automobiles. It could have, among other things, attributes that describe the interior and exterior colors, and our Start method discussed earlier. We could then extend the base class to derive or create a Pickup class, an SUV class, and a Hybrid class. These new classes would inherit all of the functionality of the Automobile class, plus add new functionality that more fully describes each of the new classes. For example, we could have an attribute in the Pickup class that specifies the maximum payload for the vehicle. Figure 14.2.1 illustrates this inheritance hierarchy.

Some object-oriented languages even allow you to create a class that inherits from more than one parent class. This feature, called multiple inheritance, allows us to create classes like HybridPickup or HybridSUV. Although multiple inheritance is supported by C++, not all languages support it.

Multiple inheritance can cause some implementation problems, especially if the two parents are derived from the same base class. This form of inheritance is called diamond inheritance because of the shape of the class diagram, as shown in Figure 14.2.2.

The problem is that since both Hybrid and Pickup objects would be composed of the attributes of the Automobile class, if an object of the HybridPickup class were instantiated, it would contain multiple copies of the attributes of the Automobile. This would cause confusion with the compiler because it wouldn't know which version of the attributes to use to build the HybridPickup object. The solution to this problem depends on the language and will not be discussed at this time.

images

Figure 14.2.1 Inheritance

images

Figure 14.2.2 Diamond inheritance

In OOP, there are two relationships that are crucial in describing the interaction of classes. The first relationship is that of inheritance, sometimes called specialization. However, there is a much less formal term to represent this relationship, “is a”. For example, a Pickup “is a” Automobile, a Duck “is a” bird, and a Student “is a” Person.

The other relationship goes by many formal names, containment, aggregation, or composition. Its informal name, “has a”, is very descriptive of the relationship. For example, an Automobile “has a” Engine. This means the Automobile class contains an instance of another class called Engine.

14.2.4 Polymorphism

The formal definition of polymorphism is “many forms.” However, if you were to give this definition as a description of polymorphism during an interview, you would probably not get the job. A better description would be “the ability of different objects to respond differently to the same message.” For example, sending the same Start message to a Pickup or Hybrid will start either vehicle even though the starting process under the hood (pun intended) is much different. Starting a gasoline-based internal combustion engine requires a much different process than starting a gas-electric hybrid engine. The valuable thing about polymorphism is that we don't really need to know what type of object we are dealing with. The message, Start, is going to be the same regardless of the type of automobile.

Section 14.2 Exercises

1.  Identify the methods and attributes associated with a tire.

2.  Identify the methods and attributes associated with a cell phone.

3.  Identify the relationship between each of the following entities:

a. bird – feathers

b. train – caboose

c. plant – fern

d. person – student – Bob

e. mammal – dog – collar

4.  Define each of the following terms:

a. encapsulation

b. attribute

c. method

d. instantiation

e. object

f. information hiding

g. implementation hiding

h. inheritance

i. polymorphism

j. class

5.  Compare and contrast interface versus implementation.

14.3 Advantages and Disadvantages

Remember that OOP is just one of several programming paradigms. Although it is one of the most popular forms of programming in industry, it doesn't mean that the other paradigms are useless or outdated; they have their own place in industry. OOP has several advantages, but these do not come without a price.

14.3.1 Models Real Life

As we've shown in our previous examples, OOP allows us to easily model the real world. Looking at your surroundings, notice that everything you see can be thought of as an object. The coffee cup has attributes that determine its size, shape, color, and contents. The methods associated with the cup could include Fill, Sip, and Guzzle, which might be useful in manipulating the object.

Being able to model the real world is an important advantage of OOP, and many applications use this ability to their advantage. One of the most popular industries to incorporate OOP within their development environment is that of computer gaming. The ability to easily populate a game with a variety of objects is very important for producing games in a timely manner.

14.3.2 Self-Contained

Well-designed objects should be able to manipulate the data or state of the object by passing messages through the object's interface. In other words, the object should be able to stand alone or be self-contained.

Another technique or practice that helps an object stand on its own is to always know the state of the object's variables. The methods that manipulate or alter the data members, known as mutators, ensure that any data stored in the data members is valid. For example, in our Engine class, the size attribute of an engine should never be negative. It is the responsibility of the mutators to keep this situation from happening.

Always knowing the state of the object's data members is also accomplished by initializing all data members. Initialization guarantees that the object is originally set to a known state. Each language has different techniques for initializing data members. Regardless of the syntax, however, the reason remains the same: the object should always know the state of its data members.

Controlling the object only through its interface guarantees that it will always behave in a safe manner and have a valid state. The ability of objects to be self-contained has other benefits as well, as discussed in the next section.

14.3.3 Code Reuse

Since objects model real-life things and are intended to be self-contained, it is often possible to reuse them in other applications. For example, if we already have an Engine class that was developed for the Automobile example, the development of a Boat class could use the Engine class for those boats that contain an engine. This stand-alone capability would make the reuse of the Engine class very simple.

In order to take advantage of this ability to seamlessly reuse these classes, care needs to be taken to design and implement classes with reusability in mind. Appropriate methods need to be created to ensure that a flexible interface is provided for the objects. These methods should also establish and maintain the integrity of the data members of the object.

Another way OOP promotes code reuse is through generic programming. Although implemented in several different ways, C++ uses templates; this feature allows a programmer to specify that a class will contain data members whose data type can change to meet the programmer's needs. For example, we could create a special container of information called a linked list. We can create this container so that it can contain any form of data: integers, Automobiles, or Pickups. The container will not need to change to be able to handle all of the different data types.

14.3.4 OOP Overhead

All of the features of OOP do not come without a cost. The extra layer of abstraction often makes program executables developed using object-oriented methodologies bigger. Some environments that have limited resources, such as many embedded systems, may find the overhead of OOP prohibitive.

14.4 String Class

Many of the OOP components discussed in this chapter can be found in the C++ predefined string class. This class is very robust and has many member functions that a programmer can use as the interface into the class. The string class acts as a wrapper around a dynamic cString. The term “wrapper” implies that the cString is encapsulated within the string class. The only way to access the cString is through the interface the string class provides.

The following sections introduce some of the more commonly used features of the string class. To use the string class, the <string> header file must be included and namespace rules must be followed.

14.4.1 Instantiation and Initialization

We've already seen the instantiation of objects. In Chapter 11, we showed the instantiation and initialization of ifstream and ofstream objects. The syntax used to instantiate these objects was exactly the same as that for primitive data types. The string class is no different. Example 14.4.1 shows the instantiation of several string objects.

images

Remember, encapsulated within the string class is a cString data member, which is dynamically allocated and assigned a value during the instantiation process. If the string object is not explicitly initialized, the string class ensures that its data member is initialized to an empty string. Therefore, printing a noninitialized string will display nothing, rather than the garbage displayed from a noninitialized cString.

14.4.2 Reading and Writing Strings

The string class has added functionality to use cin and cout seamlessly with its objects. This is accomplished by overloading the insertion and extraction operators to work with strings. Overloading is the process of providing an alternative definition for a function or, in this case, an operator. Example 14.4.2 demonstrates using I/O streams with strings.

images

images

Unfortunately, we can't use the .getline member function with strings. There is a similar routine that can be used with strings, however, called getline, and it is shown in Example 14.4.3.

images

In Example 14.4.3, the function getline is not a member function of either the string or the stream class. Instead, it takes as its first parameter the stream to read the data from, and the second parameter is the string object. You will need to flush the input buffer just as you would with the .getline member function.

14.4.3 Other String Features

Up to this point, you probably haven't seen very many advantages of using the string class over that of cStrings. In this section, some of the value of using strings will become apparent.

One advantage of using strings is that we are not required to use any of the cString functions to manipulate the string. The strcpy, strcat, strlen, and strcmp functions are all unnecessary because that functionality is encapsulated within the string class. Example 14.4.4 illustrates some of the built-in functionality of string objects.

images

images

You can see from Example 14.4.4 that many of the irritating idiosyncrasies of cStrings have been addressed and overcome in the string class. The example shows that the assignment operator can be used instead of strcpy, the + and += operators replace strcat, and even strcmp is not necessary because comparison operators can be used with strings. The .length member function even replaces strlen.

There are many other member functions available in the string class. Use the help that comes with your IDE to determine what methods are available and their uses.

The string class is very powerful because of the object-oriented principles that allow for the encapsulation of data and functions within a class. The only way to manipulate the data stored in the object is through the interface provided by the class. The implementation details can remain a mystery because of the robust interface provided.

Section 14.4 Exercises

1.  Which of the following statements are legal? Assume the following declarations.

string str1, str2 = “C”;

a. string test = ‘A’;

b. str1 = str2;

c. str2 = “C++”;

d. cout << str1[0];

e. cout << strlen( str1 );

f. cin.getline( str1, 80 );

Section 14.4 Learn by Doing Exercise

1.  Rewrite 11.14 Programming Exercise 4 to use strings instead of cStrings.

14.5 UML Introduction

The acronym UML stands for Unified Modeling Language and includes standardized symbols for use in developing, documenting, and modeling a software system or application. Like most of the other concepts presented in this chapter, UML is designed to be language-independent.

14.5.1 UML Overview

UML was originally introduced by Grady Booch and Jim Rumbaugh, and first appeared in the mid 1990s. Since its introduction it has continued to evolve, and today it plays a very important role in the development of software.

UML includes a number of types of diagrams for modeling or representing a software system, each providing a different perspective on the system. These diagrams include such tools as use cases, class diagrams, sequence diagrams, and state diagrams. While each of the tools provides valuable information, this section focuses only on a few aspects of class diagrams.

14.5.2 Class Diagrams

Class diagrams illustrate and describe the classes and their relationships within a system. To help represent or characterize a class, we use a box that includes the name of the class in the top section. Below the name, there is an optional compartment containing the attributes of the class. The final section contains the class's operations, or methods. An example of a simple class diagram is shown in Figure 14.5.1.

Figure 14.5.1 shows a diagram for our hypothetical Dog class. Class attributes include the name of the dog, its gender, and its breed. The methods include bark, shake, and sit. The combination of the attributes and methods fully describes a class.

Even though developing class diagrams is not always an easy task, this relatively simple diagram allows both the developer and the users of the system to see at a glance the major characteristics associated with a class. UML is an area that continues to gain widespread acceptance within the software development community. In the next chapter we will revisit this topic and introduce some additional characteristics often used with class diagrams to provide even more information.

images

Figure 14.5.1 Class diagram

Section 14.5 Learn by Doing Exercise

1.  Create the class diagrams for the classes created for Section 14.2 Exercises 1 and 2.

14.6 Problem Solving Applied

In this section, we will illustrate and reinforce some of the concepts presented in this chapter related to classes and to UML class diagrams. In addition, we will present some extra features that can be included within your class diagrams.

Assume that we have decided to begin the process of creating a database for our movies and music. One of the first steps is to identify the various objects we need to include within our system. After thinking about the problem, we have identified two main objects that will need to be included within our rough design: Music and Movie. After giving the problem some additional thought, we realize that both music CDs and movie DVDs contain some related information. For example, we know that both music and movies can be categorized by a specific genre. Additionally, both a movie and an album have a name and a time length associated with them. Within our example we will call this base or parent class Media.

Even though we only spent a limited amount of time dealing with objects and modeling, we know enough to draw a diagram to help us, and others, visualize some of the aspects of our classes. We begin by drawing the chart shown in Figure 14.6.1 to help visualize the inheritance relationship that exists between our classes.

Notice that both the Movie class and the Music class inherit from the Media class. Likewise, one can see that the Movie class “is a” form of Media and that the Music class “is a” form of Media.

images

Figure 14.6.1 Inheritance diagram of entertainment media

images

Figure 14.6.2 Media class and related attributes

images

Figure 14.6.3 Media class with attributes and methods

Now that the classes have been identified, we can use a UML class diagram to help us identify and show the various characteristics associated with each respective class. First we add the attributes compartment to our class diagram. Figure 14.6.2 uses a class diagram to illustrate what we know so far about the Media class.

As shown in Figure 14.6.2, the Media class contains four different attributes. Once the attributes of the class are identified, the next step is to determine the various operations required. Figure 14.6.3 shows the next revision of the Media class, along with some of its operations, or methods.

As illustrated within the operations compartment of Figure 14.6.3, the getName method has no parameters and returns a string. The operation setCost receives one value, a float, and does not indicate a return type. If no specific return type is provided within our class diagram, we can assume the method will not return a value.

Remember, both the Movie and Music classes inherit from the Media class, as shown in Figure 14.6.1. As a result, both of these classes will have all of the characteristics associated with the Media class and will also include their own unique attributes and methods.

The diagrams for both the Movie class and the Music class are illustrated in Figure 14.6.4. Remember that each of these classes had extended the functionality originally provided by the Media class.

images

Figure 14.6.4 Media class diagrams

Figure 14.6.4 shows that both the Movie and Music classes inherit from the Media class. This is represented by using a hollow triangle to show specialization.

While there are additional components or options that could be added to the various diagrams presented, it is clear that even these elementary class diagrams present another way of looking at a software system. Remember, there is much more to class diagrams and UML in general than what is presented within this short section. Undoubtedly UML will continue to evolve, and its use will continue to expand within the software industry.

 

14.7 C—The Differences

This chapter has presented OOP from a broad perspective, without any references to a specific language. However, as previously noted, C++ includes a number of extensions over the C programming language that make it much easier and faster for writing object-oriented programs. If you are doing OOP, you would usually choose C++ over C. We will have a bit more to say about the differences in the next chapter.

14.8 SUMMARY

Within this chapter we introduced a number of fundamental concepts related to the object-oriented programming paradigm. One of the first elements examined was a class. A class usually includes a number of unique features grouped together in one package. These features include attributes, or properties, and related behaviors. Once a class has been defined, we can actually instantiate an instance of a class, resulting in the creation of an object.

We presented the concept of information hiding, which helps ensure that an object is always in a valid and safe state. By using information hiding, we make it a point to protect the data members or attributes from any function outside of our own class. Only methods contained within the class can access or manipulate the class's members, helping us control the object's state. We also discussed two additional terms associated with class methods: “interface” and “implementation.” As noted, the interface represents the methods within a class that access or manipulate data. These methods are the only way that functions outside of the class can change an object's state. It is unnecessary to know the specific details behind the implementation of a method to use a class. Concealing the implementation from the user of a class is called implementation hiding.

The next section of the chapter focused on inheritance, or the ability of an object to extend the functionality of an existing class to form another class. This powerful ability greatly improves programmer productivity through an important tool that enables code reuse.

Finally, we discussed the concept of polymorphism. This rather advanced but extremely important component of object-oriented languages contains a number of aspects, including the ability of different objects to react differently to the same message.

To help see the power of OOP and how many of the terms discussed in this chapter are related to real solutions, we introduced the string class. This class is a wrapper around a dynamic cString and provides built-in functionality that alleviates some of the problems associated with cString behavior.

To aid us in designing and developing our solutions, we introduced a design tool called UML. While UML includes a number of aspects for modeling software, we focused on class diagrams. A class diagram can be used to illustrate the attributes and the methods of a specific class.

As you discovered, OOP is another powerful paradigm to use in developing software. Like almost everything else, it has both advantages and disadvantages, but we are very likely to see its continual growth and evolution in the foreseeable future.

14.9 Answers to Chapter Exercises

Section 14.2

1.  Class: Tire

Attributes:

Type: Passenger car, truck/SUV, etc.

Diameter: 14, 15, 16, etc.

Speed Rating: A1, A2, B, C, etc.

Inflation Pressure: 50, 55, etc.

Methods: Inflate, Deflate, Check Pressure

2.  Class: Cell Phone

Attributes: Dimensions, Brand, Memory, Speaker, Camera, Weight, Bluetooth capable

Methods: Turn On, Turn Off, Dial, Answer, Hang up, Store Number, Recall Number, Last Number Redial, Activate Speaker, Deactivate Speaker

3.  a. A bird has feathers.

b. A train has a caboose.

c. A fern is a plant.

d. A student is a person. Bob is a student.

e. A dog is a mammal. A dog has a collar.

4.  a. Encapsulation:

The ability to include the attributes that describe the object and the functions that manipulate the data into one container.

b. Attribute:

The data members that make the individual object unique.

c. Method:

Functions that are encapsulated within a class.

d. Instantiation:

Declaring a variable from a specific class, resulting in memory being allocated.

e. Object:

The variable that results from the instantiation or declaration of a variable from a class.

f. Information hiding:

The process of concealing the data members of a class, helping to ensure that only the class's methods can change the state of its data members.

g. Implementation hiding:

Hiding the actual implementation of a function or method from the user of a class.

h. Inheritance:

The ability to take an existing class and extend its functionality to form another class.

i. Polymorphism:

The ability of different objects to respond or act differently to the same message.

j. Class:

Contains the data, or attributes, that describe the object and the functions that manipulate the data into one container.

5.  The interface represents the methods of a class through which functions outside the class manipulate the actual data contained within the object. The user need only know the interface to be able to effectively use the class. Implementation relates to how the methods actually perform their respective jobs and is usually hidden from the user of the class.

Section 14.4

1.  a. Illegal—must use a string or cString

b. Legal

c. Legal

d. Legal

e. Illegal—the strlen function expects a cString, not a string

f. Illegal—using the wrong getline; you need to use:

getline( cin, str1 );

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.14.98