[Table of Contents] [Previous] [Next] [Object Central Home]

The Essence of Object-Oriented Programming

Copyright © 1998, Bruce E. Wampler

    2.1  What is Object Orientation?
         2.1.1  What Is An Object-Oriented System?
    2.2  Objects and Classes
        2.2.1  Objects
        2.2.2  Classes
        2.2.3  Class Hierarchies
        2.2.4  Polymorphism
        2.2.5  Base Classes
        2.2.6  Parameterized Classes
    2.3  Other OO Terminology
        2.3.1  Encapsulation
        2.3.2  Object
    2.4  Chapter Summary


Chapter 2
Objects and Classes

2.1  What is Object Orientation?

So, what exactly is Object Orientation? It represents a fundamentally different way of thinking about problem solving than other software development methodologies. Basically, it is a technique of modeling some kind of system in software based on objects. An object is the core concept, and is a model or representation of a real-world entity or logical idea or concept. Considering a real-world system, you might model a temperature sensor as an object. Or, in a more abstract system, you might model something like a color as an object. You can even consider something as basic as a number as an object that has a value and a type. Typically, each object has an associated set of attributes such as value, state, or whatever else is needed to model the object. For example, a sensor might include state such as active or inactive, an attribute such as its current value, and information about its physical location.

Individual objects don't stand alone. They belong to a collection of other similar objects that all are members of the same group, or class. Classes and objects are closely related, but are not the same thing. A class is a description or definition of the characteristics of objects that belong to that class. An object is a single instance or member of a class. There can be many instances of objects of a given class, but all members of a class have similar behavior.

For example, there might be a class called sensor used to model sensors. The class would define the characteristics of all sensors. Each individual physical sensor in the system would be represented be as object belonging to the class, and have specific values for the attributes described by the class definition.

The class description includes the means of accessing and changing the state of individual object members of that class. One common representation of color is called RGB, where the color is specified by the values of its red, green, and blue components. A color class description would provide the means of both retrieving and setting the RGB values of a color object.

It is also typical to describe one class based on a different class - either by extending the description of a higher level class, or by including the description of another class within the current class. For example, you might create a class that describes the general characteristics of all sensors, and then more specialized classes that describe specific sensors such as temperature or pressure.

We will refine the definitions of an object and a class later, but objects and classes are really the heart of Object Orientation. OO software systems consist of objects of different classes that interact with each other using well defined methods or services specified by the class definitions. This represents a totally different software paradigm. To produce successful OO designs and programs, it is important to switch your thinking so that everything becomes a well-defined, self-contained object that interacts with other objects in well-defined ways.

2.1.1  What Is An Object-Oriented System?

An Object-Oriented System is one that has been designed with the following characteristics:

  1. Abstraction

    An abstraction is a mechanism that allows a complex, real-world situation to be represented using a simplified model. OO methodologies abstract the real world based on objects and their interactions with other objects. For example, the RGB model is one possible abstraction of a color.

  2. Encapsulation

    The abstractions are encapsulated into objects. The states and behaviors of the object are incorporated into an encapsulated whole or class. The actual internal implementation is hidden from the rest of the system. While this not a new technique, in OO the encapsulation is an inherent and integral part of the system and design. For example, as long as the outside world continues to see a color as a consistent RGB value, it wouldn't matter just how a color object represented RGB internally. It could could use the HSV (hue, saturation, value) color model internally if needed, and the outside world would be unaffected.

  3. Hierarchies

    In an OO design, classes of objects are arranged in hierarchies that model and describe relationships among the classes. There are two basic ways to build hierarchies. The first is to include other classes as part of one class. For example, consider a a dialog graphical user interface class. Such dialogs usually contain command buttons and other controls to interact with the user. Thus, a dialog class might include control classes such as buttons or lists as part of its definition.

    The second way is to build a hierarchy is to define more specialized classes based on a higher-up generalized class. For example, a dialog class can be considered a specialized case of a more general window class. These hierarchies are built to reflect the characteristics of the problem being modeled. Any class can be defined using a combination of both kinds of hierarchy.

  4. Communication via messages

    Objects interact with other objects, either from the same class or different classes. This interaction is done by sending messages (usually by function calls) to other objects to pass information or request action. For example, when a user selects a command button in a dialog, a message would be sent to the dialog object notifying it that the command button was PRESSED.

These four points represent the essence of an object-oriented system. Slightly different terminology or other points may be used elsewhere, but abstraction, encapsulation, hierarchies, and communication via messages are really at the heart of the matter.

It is also important to understand the following points.

2.2  Objects and Classes

Objects and classes are related, but are not the same thing. Each individual object is a single instance of a class, something that exists. It is said to be a member of a given class. A class is the description of the attributes and behaviors of all members of that class.

2.2.1  Objects

An object is a thing or concept. It can be a real-world thing or concept, or an abstraction of a thing or concept expressed as a software representation. An object has state and behavior. State is expressed by attributes, and behavior is expressed by the methods1 associated with the object. State usually reflects changeable attributes of an object. Objects can also have nonstate attributes (e.g., serial number). Individual objects, also called instances, have identity and are distinct things, and can be distinguished from other objects.

Some Examples of Objects

Almost anything you need to model in software can be considered an object - a temperature sensor in a control system, a person in a subscription system, a room of a building, a word in a sentence. Each of these objects has attributes and needs methods to manipulate it.

Consider a graphical user interface such as X or Windows. One type of object included in such an system is a dialog interface. One state attribute of the dialog object might be its size on the screen, while a nonstate attribute might be a list of command buttons it includes. Behavior of a dialog object might include changing which command buttons are displayed or active at any given time, or responding to a message that a button has been selected.

2.2.2  Classes

A class is a description of a collection of objects with common attributes and behavior. In practice, the definition or specification of a class includes the definitions of the attributes comprising the state, the methods implementing the behavior, and how to handle creation and destruction of an object. A class is identified by a name.

In C++, a class is an extension of a struct. The attributes of a class are defined by declaration of variables of various types. A C++ class also includes member functions which are used to implement the methods of a class. The member functions are integral parts of the class definition. The details of C++ are covered in more detail in Part 2.

An instance of a class is called an object, or equivalently an instance. There may be classes that are not represented by an object, in which case the class is called an abstract or base class, and is usually intended to be extended by subclasses. A class called Animal would be a base class because there never would be an instance of a general object called an Animal. Instead, there would be more specialized subclasses of Animal such as Horse or Snake which would have instances.

2.2.3  Class Hierarchies

The real heart and soul of object-oriented design is the arrangement of classes into hierarchies. There are two ways to organize class hierarchies.

The first is to include one class as a part of another. This is called a whole/part hierarchy, and is characterized by a "has a" relationship. For example, a library is made up of a collection of books, which are themselves collections of pages, and so on. A library has some books which have some pages. You can also look at this as a "part of" relationship. A page is a part of a book which is part of a library.


Figure 2.1: A Book Whole/Part Hierarchy

The second kind of class relationship is the generalization/specialization hierarchy. Generalization/specialization (or gen/spec for short) is characterized by an ïs a" relationship. For example, if you were designing a class hierarchy to model animals, you might have a class for dog, which is a specialization of the class carnivore, which is a specialization of the class mammal, and so on. Key to this concept is the fact that a dog is a carnivore which is a mammal which is an animal2.


Figure 2.2: An animal Generalization/Specialization Hierarchy

Object-oriented programming languages have differing levels of support for whole/part and generalization/specialization hierarchies. Most OO programming languages, including C++, haven't defined special language support for whole/parts. Nevertheless, whole/part hierarchies are critical for most OO designs. The common OO term for a whole/part hierarchy is aggregation.

It is easy to define aggregation in terms of existing programming language features. There are two ways to implement a whole/part relationship. In practice, the most common way to implement aggregation is to include a pointer to an instance of the aggregate object. For example, the definition of a book class could include a pointer to an instance of the page class (or more likely, a list of pointers to pages). The other way is to include a declaration for a variable of the type of the aggregate object3. For example, you could include a declaration for a variable of type page class within the definition of the book class. Using pointers generally leads to more efficient code.

All major OO programming languages include direct language support for generalization/specialization. The main mechanism for implementing a gen/spec hierarchy is called inheritance4 With inheritance, a new subclass is derived from an existing parent superclass. Not only does the derived subclass inherit the properties of the superclass, but it can extend and modify those behaviors and attributes.

The superclass is extended without altering its definition or source code, and the subclass can be selective about which properties of the superclass it inherits. The subclass extends the superclass by adding new properties, and by selectively overriding existing properties of the superclass.

Inheritance is an especially important and powerful concept. It means that an existing class can be used as-is by a new class, and its properties modified and extended through the inheritance mechanism. Classes can be designed to provide useful default behaviors and attributes which can be extended and modified only if the derived subclasses needs to.

Consider the mammal hierarchy. All mammals share a number of common characteristics. These can be captured once in a generalized mammal class. The general mammal characteristics are then available by inheritance to more specialized subclasses such as carnivores or rodents. The class carnivore inherits all the general characteristics of a mammal such as having hair and bearing live young which are fed milk, while extending the attributes to having certain kinds of teeth, and the behavior to eating meat. The rodent subclass of mammal would extend the mammal superclass with different attributes than a carnivore. The mammal class itself could be derived from an even more general animal class.

This really represents an economy of expression. We can describe the general characteristics in a superclass, while expressing the specializations in a subclass. We don't need to repeat all the general characteristics for each instance of a mammal, just those specific to the subclass. And when the behaviors of different subclasses vary, such as the eating habits of different specific mammals, these too can be specialized in a subclass.

There are two kinds of inheritance. If a subclass only uses one superclass, it is using single inheritance. A class can also be defined that inherits from more than one superclass. This is called multiple inheritance. Not all OO programming languages support multiple inheritance, although C++ does. Compared to single inheritance, multiple inheritance is used infrequently. For modeling certain situations, however, multiple inheritance can be invaluable.

Note that the is a relationship is critical. If a subclass cannot be defined with an is a relationship to its superclass, then there is not an inheritance relationship. A Dog is a Mammal, but it is not a Rodent or a Color. You should always apply the is a test when designing inheritance hierarchies.

2.2.4  Polymorphism

For a given class hierarchy, it is possible for different subclasses to be derived from a common superclass. Each of the subclasses can override and extend the default properties of the superclass differently. Polymorphism is a characteristic of inheritance that ensures that instances of such subclasses behave correctly.

When a subclass overrides a default method, it uses the same name as in the superclass. If the behavior of the default method is adequate, a given subclass does not need to override the method, even if other subclasses do. The derived method can implement completely new behavior, or use the default method while extending it with additional behaviors.


Figure 2.3: Polymorphism means a Cat uses its own EatMeal, a Dog uses the Carnivore EatMeal, and a Rodent the Mammal EatMeal.

Figure 2.3 shows an Animal hierarchy. Since all mammals need to eat, there would likely be a general method5 defined by the Mammal class to handle eating, called EatMeal, for example. While all mammals might share some eating behaviors which are defined in the general mammal EatMeal method, some would require some specialized eating behaviors that are different than other mammals. The eating habits of dogs are different than cats, which are different than rodents, which are different than primates. Thus, each subclass definition can include an EatMeal method that implements the specialized eating for that subclass. Not all subclasses need implement a specialized method if the superclass method is satisfactory. In Figure 2.3, the Dog uses the more general Carnivore EatMeal, while the Cat has its own specialized EatMeal. The Rodent uses the general Mammal EatMeal. Since all animals may not need an EatMeal, there is no EatMeal method defined by the Animal class. Note that all these methods have the same name, EatMeal, even though they implement different behaviors.

If the system were to process a mixed list of different mammal objects, then it would need to use the appropriate EatMeal method for each mammal. For example, if the mammal were a dog, then the EatMeal method defined for the class carnivore would need to be used, and not the EatMeal for a rodent.

Polymorphism is what allows the appropriate method for any given object to be used automatically. Polymorphism goes hand in hand with inheritance and classes derived from a common superclass. Polymorphism almost seems like magic. It can be difficult to really believe that the proper EatMeal will be used for each object. Fortunately, polymorphism is easier to use than it is to understand completely, and you won't have to think about it explicitly most of the time. Using it comes automatically, and seems a natural part of using objects with inheritance. Just trust it. It works!

2.2.5  Base Classes

When building a class hierarchy, it is common to design some classes that will never have any instances, and are intended to be used only by subclasses. For example, the Animal class in the animal hierarchy is such a class. There will never be an instance of an Animal. These are called abstract classes. Abstract classes usually specify methods that all subclasses must override and define. For example, the Animal class might define a method called Reproduce. Since all animals reproduce, each subclass would have to define a Reproduce method. But the definition of Reproduce for the Animal class would be empty since it is an abstract class, and serves as a guideline or specification for derived subclasses.

A concrete class, on the other hand, is one that can have actual objects or instances. A Dog or Cat is an example of a concrete class because there will be instances of Dog or Cat.

A related concept is the base class. In any hierarchy, the base class is at the top of the hierarchy, and does not have a superclass. The base class in the hierarchy we've been using is animal, but it could even be more general (for example, Life) if necessary. A base class may or may not also be an abstract class.


Figure 2.4: Relationships shown by this ``class forest'' include: A, P, and S are base classes. P is a superclass of Q. B is a subclass of A, and D is a subclass of B. B and C are both derived from the common superclass A, using single inheritance. U is derived from both R and S using multiple inheritance. D, F, G, T, U, and V will certainly be concrete classes since they are at the bottom of the hierarchy, but any other class could be, too.

An OO system can have many base classes for different object hierarchies. This can be visualized (Figure 2.4) as a forest of class trees. Some OO languages require that all classes be derived from a single base class (which is usually system defined). There are various advantages as well as disadvantages to this requirement. C++ does not require this.

It is most common to override the methods of a superclass rather than the attributes. C++ requires you to distinguish methods (member functions) that you will override by calling them virtual functions. When a class is intended to be an abstract class (one with no instances), then it will define what is called a pure virtual function in C++ terminology.

2.2.6  Parameterized Classes

Basic data structures such as stacks or lists can be considered classes that are made up or contain of other objects. These are often called container classes. Methods of a stack would include push, pop, and top, for example. Attributes would include how many items are on the stack, and the objects contained on the stack. Other common container classes include queues, dequeues, trees, tables, associative arrays, and the like.

Because container classes can hold arbitrary objects, many object-oriented programming languages allow the specification of generic or parameterized classes. This allows the implementation of a container class without specifying the exact type of the objects. C++ provides the templates for defining classes that can be used with different objects.

While container classes and parameterized classes can play an important role in real OO systems, they are not really essential for understanding OO design and programming. This book won't have any more significant discussion of this topic.

2.3  Other OO Terminology

As with any other specialized discipline, object orientation has its own vocabulary. We've already covered many OO terms. This section will cover some other important terminology.

2.3.1  Encapsulation

Encapsulation is a very important part of OO. It is what allows each object to be independent. The exact implementation attributes and of object behavior is hidden from the rest of the world through encapsulation.

A class should never allow direct access to state information by the outside world. Instead, it provides methods for accessing the state. A selector is a method that gets information about the state of an object without altering the state. A modifier is an method that alters the state of an object.

An iterator is a method used to access or visit each part of an object. This allows the outside world controlled access to all important parts of an object without the need to know the internal implementation details of a specific object.

Private, protected, and public are access concepts within a class. Private data and methods are available only to instances of the immediate class. Protected items are available to other classes directly derived from the class. Public items are available to the world. It is usually best to keep all data items and structures private or protected, and allow public access to a class only through public methods.

A friend is a class or function6 that has access to protected data even though it is not a direct subclass of a given class. Friend access is often needed to allow access in has-a relationships.

2.3.2  Object

When an instance of an class first comes into existence, it is said to be instantiated. Instantiation of an object can involve considerable overhead, especially in C++.

In C++, when an object is instantiated or created, the system will automatically invoke a special function called the class constructor. It is the job of the constructor to be sure every object has a well-defined initial state. For complex objects, construction can be a very complex activity, causing significant computation and allocation of storage space, and even instantiation of other objects. There are different kinds of constructors depending on what caused an object to be instantiated. The chapter on deep and shallow object semantics covers constructors in more detail.

When an object goes out of existence (when exiting from a function, for example), the system calls its destructor. A destructor is an operation that destroys an object and frees whatever resources the object used. It is invoked when an object ceases to exist, such as when it goes out of scope.

Some objects, such as documents or data bases, whose existence transcend time are said to be persistent. Persistent objects usually provide methods that save and restore their own state (to disk, for example).

2.4  Chapter Summary


[Table of Contents] [Previous] [Next] [Object Central Home]

Visits:


Footnotes:

1 In C++, methods correspond to functions. We will use the term method in this book since it is more closely associated with objects, and reflects the fact that a method is part of a class definition, and is conceptually different than a plain function. Attributes are represented in C++ as declarations of variables of some type.

2 These may not be exactly biologically correct, but they serve our purpose for this example.

3 In C++, a class name is used to declare the type of a variable. For example, you might declare an instance of a page object as Page titlePage.

4 Support for inheritance can be considered one of the main requirements for a programming language to be called object-oriented.

5 A method is called a member function in C++.

6 OO systems will have functions or procedures that are not members of a any class. It is sometimes useful to allow these outside functions access to the internals of a class.