9.1. Classes And Objects

Time: 00:05:29 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides: PDF, PPTX
Review

Rumbaugh et al.1 succinctly summarize two ways that the object-oriented paradigm benefits software development:

Object-oriented modeling and design is a way of thinking about problems using models organized around real-world concepts. The fundamental construct is the object, which combines both data structure and behavior in a single entity (p. 1).

Software developers view problems through an object-oriented lens, matching the problem's real-world components to corresponding programming features characterized with object-oriented terminology. Object-orientation is both a way of approaching problems and of implementing their solutions, with objects serving as the fundamental construct. Today, object-oriented practitioners typically refer to the data structure and behavior as attributes and operations, respectively.

Object-orientation forms a bridge that spans the entire software development process, joining analysis, design, and programming. Unlike earlier software development processes that suffered paradigm shifts (abrupt changes in how developers represent the problem) between phases, object-orientation maintains a consistent object-based vocabulary throughout the development process.

The object-oriented paradigm encompasses three essential concepts: encapsulation, inheritance, and polymorphism. The textbook presents inheritance and polymorphism in subsequent chapters. However, encapsulation is the hallmark of objects and the ideal place to begin.

Encapsulation

Encapsulation combines attributes and operations (Rumbaugh's data structure and behavior) into an entity that computer scientists refer to as an object. Objects isolate and protect their data, blocking direct access by functions and other objects, allowing indirect access or use only through their operations. All the object's operations can use or modify its attributes, forming an intermediate scope between local and global. The intermediate scope allows limited, identifiable function coupling while preventing it from becoming difficult to locate and manage.
An object viewed as two rectangles. The top rectangle, drawn with a solid border, represents the object's attributes or data. The solid border suggests that the object conceals or protects its attributes, making them inaccessible to outside entities. The bottom rectangle, drawn with a dashed border, represents the object's operations or functions. The object exposes its operations to outside entities, controlling the access to and use of its attributes.
Encapsulation. Objects imply encapsulation, making encapsulation a synonym for objects. Wirfs-Brock & Wilkerson2 list some of the benefits of object-oriented programming, suggesting that they derive from the early adoption of encapsulation.
Object-oriented programming languages support encapsulation, thereby improving the ability of software to be reused, refined, tested, maintained, and extended. The full benefit of this support can only be realized if encapsulation is maximized during the design process (p. 71).

A class can describe many objects having the same attributes and operations. A common metaphor is to think of a class as a cookie-cutter and the individual objects as the cookies. The cookie cutter defines the size, shape, and decoration of each cookie. We can use the cookie cutter to stamp out as many cookies as we want, and each cookie will have the same size, shape, and decorations as the others. However, we eat the cookies, but not the cookie cutter; similarly, objects, not classes, do the work in a program. C++ programmers call attributes and operations member3 variables and functions, respectively. Like all variables, member variables have a type and a name. Similarly, member functions have a name, a parameter list (which may be empty), and (except for constructor and destructor functions) a return type. Rumbaugh et al.1 collectively refer to attributes and operations as features, a practice the text continues.

Attributes

Attributes are the values saved in an object. Ideally, each attribute is a quality or characteristic inherent in the entity the class represents - some aspect whose value helps distinguish between different instances or objects of the class.

  • string name;
  • double height;
  • int weight;
  • Person p1;
  • Person p2;
  • Person p3;
Attribute examples. Imagine a class named Person. Depending on how a program uses the class, typical attributes may include a name, height, and weight, each carrying important descriptive information. C++ implements attributes as member variables declared in the class's specification, so every object instantiated from the class will have these variables. Although every Person object has the same three member variables, they can store independent values: the name, height, and weight stored in p1 may differ from the values stored in p2 and p3. The compiler allocates memory for member variables inside objects, allowing programs to treat objects as a whole, single variable.

Operations

Operations represent the services an object can provide to an object-oriented client or application program. Recall that C++ is a hybrid language, meaning it supports "regular" functions, unrelated to classes, and functions that are class members. In C++, class member functions correspond to object-oriented operations. Most member functions follow the same syntax used in the preceding chapters: they have a header (the return value type, the function name, and the argument list) and a body.

Operation details. Classes define four kinds of operations or functions, distinguished by their use rather than by their syntax. Constructors and destructors are the exception.

Class Responsibilities

Ward Cunningham (Fowler4, pp. 62-63) introduced class-responsibility-collaboration (CRC) cards in the early days of industrial object-oriented software development. CRC cards consist of physical index cards on which developers write the name of a class, its responsibilities, and the names of other classes with which it collaborates. Rearranging the cards while discussing various ways a program can use the class helps developers determine which class to make responsible for maintaining various data items and providing the services a program needs to solve a given problem. The determination is relatively simple when a program uses few classes, but it becomes more challenging as the number of classes and their collaborations increase. For example, imagine two classes: Contractor and Project. Furthermore, imagine that the application tracks the contractor's pay rate and the number of hours worked. Which is responsible for maintaining the data? It's possible to create scenarios favoring each choice, and the text returns to this problem in a subsequent chapter, presenting various implementation options.

Feature Visibility

C++, like Java, controls the visibility of class features with a set of keywords (in order of increasing visibility): private, protected, and public. Although the C++ syntax is a little different than Java, the meanings of the keywords are the same in both languages, as summarized by the following Venn diagram.

A Venn diagram illustrating the private, protected, and public keywords. 'Private' restricts access to class scope; 'protected' extends access to subclasses, and 'public' allows access from all program parts.
C++ feature visibility conceptualized as a Venn diagram. Note that the effects of these keywords are at the class level rather than at the object level. The effect is especially significant when using the private keyword. The private features of objects instantiated from different classes are mutually inaccessible, while objects instantiated from the same class may access each other's private features unrestricted. See the Time and Fraction demonstrations later in this chapter for examples.

C++ Class Specifications

C++ classes differ in two important ways from Java classes. First is the obvious difference in how they use the public and private (and later the protected) keywords. The features in a Java class are individually declared as public or private. Alternatively, in a C++ program, regions within the classes are labeled as public or private. Second, Java always includes method bodies inside the class. C++ programs can define short member functions inside of a class (and doing so makes them inline functions, without the need to use the inline keyword), but programmers should only prototype larger functions in the class and write the bodies in a separate compilation unit (i.e., another .cpp file). For example:

class Time
{
	private:
		int	hours;
		int	minutes;
		int	seconds;

	public:
		Time();
		Time(int h, int m, int s);
		Time(int s);

		Time	add(Time t2);
		Time*	add(Time* t2);

		void	print();
		void	read();
};
A C++ class specification. All the features included in a class specification are said to be members of the class, which results in two important terms:
Member variables
Variables defined in class-scope. For example: hours, minutes, and seconds.
Member functions
Functions defined in class-scope. For example: add, print, and read. Three functions, all named Time, are constructors (introduced later in the chapter) and are also members of the Time class.

Class And Object Summary

Although the above class is a simple example, there are several important observations we can make:


  1. Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F., & Lorensen, W. (1991). Object-Oriented Modeling and Design. Englewood Cliffs, NJ: Prentice Hall.
  2. Wirfs-Brock, R.; Wilkerson, B. (1989). "Object-oriented design: a responsibility-driven approach." Conference Proceedings on Object-Oriented Programming Systems, Languages and Applications. OOPSLA 1989 Proceedings, October 1-6.
  3. You may see some variation in terminology between different authors. Historically, authors called the variables declared inside a class either a member or a static variable (covered in detail later in the chapter). Alternatively, some authors refer to all variables declared inside a class as member variables and further categorize them as either instance variables or class variables (also detailed later). I learned and used the first terminology as a professional software engineer. Furthermore, static or class variables are uncommon. Consequently, I use the first terminology throughout the text but explicitly state when I'm discussing static or class variables. The variations also apply to functions, although less commonly.
  4. Fowler, M. (2004). UML distilled: A brief guide to the standard object modeling language. Boston: Addison-Wesley.