[DBPP] previous next up contents index [Search]
Next: 5.2 CC++ Introduction Up: 5 Compositional C++ Previous: 5 Compositional C++

5.1 C++ Review

 

We first review some of the basic C++ constructs used in the rest of this chapter, so as to make subsequent material understandable to readers familiar with C but not C++ . Readers familiar with C++ can skip this section.

With a few exceptions, C++ is a pure extension of ANSI C. Most valid ANSI C programs are also valid C++ programs. C++ extends C by adding strong typing and language support for data abstraction and object-oriented programming.

5.1.1 Strong Typing and Memory Management

ANSI standard C introduced function prototypes to the C language. A function prototype defines the type of each function argument and the function's return value (the function's signature ). For example:

/* A forward declaration to a_function */
int a_function(float b, double c);

/* The definition of a_function */
int a_function(float b, double c) {
  /* Function body */
}

C++ requires that function prototypes be provided for all functions before they are used and enforces consistent function use between program   files. Thus, it is possible to distinguish between functions that have   the same name but different signatures. C++ uses this capability to allow function names to be overloaded. That is, more than one function can be defined with the same name; the compiler compares function call arguments with function signatures to determine which version to use.

In C programs, the library routines malloc and free are used for dynamic memory allocation. C++ defines two additional operators, new and delete, as illustrated in the following code fragments.

struct S { 
   /* Structure body */
};

S *sPtr = new S;         /* Allocate instance of S */
delete sPtr;             /* Delete instance of S */

int *iPtr = new int[25]; /* Allocate array of integers */
delete [] iPtr;          /* Delete array of integers */

Notice that new is given a description of the type of the data object to be allocated; it returns a pointer to dynamically allocated data of that type. The delete operator is used to release dynamically allocated storage. The programmer must indicate when an array of objects is being deleted.

5.1.2 Classes

  The most significant feature that C++ adds to C is the concept of   classes. A class can be thought of as a generalization of a C   structure. In C, a structure groups together data elements of various   types under a single name; in C++ , structures can also contain member functions. Like data elements of a C structure, member functions of a class can be accessed only through a reference to an object of the appropriate type. In C++ , a class defines a scope in which names referring to functions and data can be defined. Classes can be introduced using the C keywords struct and union or the C++ keyword class.

 

Program 5.1 illustrates various features of the C++ class mechanism. This program defines a class named Datum containing a data member x, a member function get_x, and two constructor functions. (Notice the C++ single-line comments; anything after a double slash // is a comment.) These terms are defined in the following discussion.

The syntax Datum::get_x() is used to name a member function get_x of Datum. This name, called a quantified name, specifies that we are referring to a function defined in the scope of Datum. If we do not quantify the name, we are defining the global function get_x(), which is a different function. Notice that within the definition of Datum::get_x() we can refer to the data member x directly, because x and get_x are defined in the same scope. We also could incorporate the definition for function get_x directly in the class definition, as follows.

public:
   int get_x() { return x; }
   ...

  The two member functions named Datum are constructor   functions for the Datum class. A constructor has the same name as the class to which it applies and, if defined, is called whenever an object of the appropriate type is created. Constructor functions are used to perform initialization and can be overloaded.

The function test in Program 5.1 creates and uses three Datum objects, two of which are declared in the first two lines in the function body. Notice that the class name Datum can be used directly; in C we would have to write struct Datum. In the third line, the new operator is used to allocate the third Datum object.

Because constructors have been defined for Datum, they will be called whenever Datum objects are created. The constructor with no arguments, called a default constructor, is called when   a_datum is created, thereby initializing the field x of a_datum to zero. The declaration of another_datum and the new operator both specify an integer argument and hence use the second constructor, thereby initializing the variable x to 23 in these two cases.

Recall that in C, the fields of a structure are accessed by using the dot operator ( struct.fieldname), while the fields of a structure accessible via a pointer are accessed with the arrow operator ( structptr->fieldname). As illustrated in the function test, these same mechanisms can be used to refer to the member functions of a C++ class.

The C++ class mechanism also supports protection. Members of a C++ class can be designated as being either public or private. A public class member can be used without restriction   by any program that has a reference to an instance of a class. Public   data members can be read or written, and public member functions may be called. In contrast, private members can be accessed only from within the class object. Private data members can be accessed only by a class member function, and private member functions can be called only from within another member function of the class. For example, the variable x in the Datum class is a private variable and hence can be accessed by the member function get_x but cannot be referenced directly as a_datum.x.

5.1.3 Inheritance

 

The final C++ feature described here is inheritance. As in C, a   class or structure can be included as a member of another class, hence   defining a has-a relationship between the two classes. In C++ , inheritance is used to create an alternative relationship between classes, an is-a relationship. If a class D inherits from class B, then all public members of B are also members of D. We say that D is derived from B, and that D is a derived class while B is a base class. D includes all public members of B and may also include additional members, which are defined in the usual way. We can view D as being a specialized version of a B, hence the is-a relationship.

Program 5.2 illustrates the use of inheritance. The syntax for inheritance is to specify a list of base classes after the derived class name. The base class list is separated from the derived class name by a colon. The keywords public and private   are associated with the base class names to specify whether the inherited members are to be public or private members of the derived class.

Members of the base class can be redefined in the derived class. For example, in Program 5.2 class D redefines func2. When func2 is called from an object of type B, we access the version of func2 defined in B. If func2 is called from an object of type D, we get the version of func2 defined in D.

 

In some situations, we may want a base class to call functions that are defined in a derived class. This facility is supported by a C++ mechanism called virtual functions. A function declared   virtual in a base class can be defined in a derived class. This   feature, which allows a programmer to specialize a generic base class for a specific application, is used in Section 5.8.2 to build a reusable parallel library.



[DBPP] previous next up contents index [Search]
Next: 5.2 CC++ Introduction Up: 5 Compositional C++ Previous: 5 Compositional C++

© Copyright 1995 by Ian Foster