4.8 Controlling Change


Variables, methods, and parameters may be declared such that their ability to cause change or be changed is restricted. A variable may be limited so that it has a constant, unchanging value, a method limited so that it does not change the object on which it is operating, and a parameter limited so that it cannot be changed by the method to which it is passed.

Limiting variables, methods, and parameters in this way is useful for three reasons. First, the additional declaration provides a more specific statement of the intention of the programmer. Often these intentions cannot be expressed and are, perhaps inadvertantly, violated, causing unintended behavior and system errors. With the additional declaration, the compiler is able to detect and prevent unintended usage. Second, when errors do occur, the additional declarations help to reduce the area of the system that must be examined. If data has been improperly changed, the direct cause cannot be in those areas declared not to cause or allow such changes. Third, the additional information often helps the compiler to better optimize the executable code. For example, if the compiler knows that a variable cannot change, it need never generate code that would save and restore its value.

In C++ the keyword const is used as a modifier on declarations of methods, variables, and parameters to indicate a limitation on its ability to cause change or be changed. The keyword appears in different positions in a declaration depending on whether it is applied to a method, a variable, or a parameter. Also, the use of const with pointers is a little more difficult to understand, as will be seen below.

The enforcement of const properties is done by the compiler. Thus, for example, a compile-time error will result if an assignment is attempted to a constant variable or object. An error will also be detected at compile-time if a constant method that attempts to change some part of the object's data is written.

Constant Variables and Objects

The simplest use of the const attribute is with variables and objects, in which case its purpose is to specify that the variable or object cannot be changed. This allows variables and objects to have a value that is guaranteed to remain unaltered during the execution of the program. Examples of values that should be declared const include mathematical constants (e.g., the value of pi), system limits (e.g., array bounds), program conventions (e.g., a code or value for a flag), program information (e.g., a version number), and fixed application information (e.g., the default location of a standard dialog window); code for these constants looks like this:

       const double Pi = 2.141598;                     // mathematical constant
        const int MAX_ARRAY_LENGTH = 100;               // system limit
        const int YesAnswer = 0;                        // program convention
        const int  NoAnswer = 1;                        // program convention
        const int VersionNumber = 1;                    // program information
        const int ReleaseNumber = 5;                    // program information
        const Location dialogLocation (200,200);        // application information

Notice that both built-in types (int, double, etc.) as well as objects of user-defined classes (e.g., Shape) may be declared constant. Also notice that variables declared const must be given an initial value when they are declared, as there is no other way to provide a value for the variable - since it is const it cannot be altered after it is declared.

As discussed, assignments to constant variables or objects are detected as errors by the compiler. For example, using the above declarations, the statements:

       Pi = 2.5;
        NoAnswer = 2;
        dialogLocation = Location(100,100);

would all be detected as compile-time errors.

Constant Methods

The keyword const, when used as a modifier on the declarations of a method, indicates that the method does not change the object to which the method is applied. A modified version of the Location class below shows how the const modifier is used on methods. For the purposes of this example, two other methods that change the values of the coordinates maintained by the Location, setX() and setY(), are added.



Constant Methods in the Location Class
 class Location {                         // Extension 1
   private:

     int  currentX, currentY;

   public:

          Location(int x, int y);         // specific location
          Location();                     // default location
     int  Xcoord() const;                  // return x-axis coordinate
     int  Ycoord() const;                  // return y-axis coordinate
     void setX(int newx);                 // change x coordinate
     void setY(int newy);                 // change y coordinate
   };
   // the implementation follows

    Location::Location( int x, int y ) { currentX = x; currentY = y; }

    Location::Location () { currentX = -1; currentY = -1; }

int Location::Xcoord() const { return currentX; }
int Location::Ycoord() const { return currentY; }
void Location::setX(int newX) { currentX = newX; }

void Location::setY(int newY) { currentY = newY; }



In this code the const modifier is used to declare that the two methods Xcoord() and Ycoord() do not change the Location object on which they operate. These two methods are typical of const methods: they return information about the object without changing the object itself. Methods of this kind simply query the object without altering it. The two methods setX() and setY() cannot, however, be declared const because they do change the object to which they are applied.

Note in the above example that the const modifier must appear both where the method appears in the class definition and again in the implementation part where the method's implementation is given.

Constant methods may be applied to a constant object. Because the constant method does not change the object, the use of a constant method does not violate the object's constant property. For example:

       const Location dialogLocation (200,200);        // application information

        ...

        int dialogX = dialogLocation.Xcoord();          // OK
        int dialogY = dialogLocation.Ycoord();          // OK

        dialogLocation.setX(300);                       // ERROR

In this example, the constant methods Xcoord() and Ycoord() may be applied to the constant object dialogLocation. However, non-constant methods, like setX(), cannot be applied to a constant object because they may change the object thus violating the constant property of the object.

An object that is not constant may be the subject of constant and non-constant methods. For example:

      Location loc(300,300);            // not a constant object

       ...

       int x = loc.Xcoord();             // OK
       loc.setX(x+20);                   // OK - can change object

In this example, the object "loc" is not a constant object. Thus, any valid method may be applied to this object, const and non-const methods alike.

Constant Parameters

The const modifier is often used in conjunction with parameters that are passed by reference to achieve the safety of passing by-copy while at the same time achieving the efficiency of by-reference. Recall that by-reference is more efficient because it does not create a copy of the object being passed, which efficiency is particularly important when the object is large (e.g., a megabyte-sized jpeg image).

A different extended version of the Location class is shown below to illustrate how const is used with a by-reference parameter. This extended definition adds a new method that tests whether the coordinates defined by a Location object are the same as the coordinates of a Location object that is passed as a parameter. The parameter object is passed by-reference to avoid any cost associated with passing the object by copy, and the parameter is declared const because it is not necessary to modify the parameter object to determine whether the two Locations are the same.


Constant Parameters in the Location Class
 class Location {                         // Extension 2
   private:

     int  currentX, currentY;

   public:

        Location(int x, int y);         // specific location
        Location();                     // default location
     int Xcoord() const;         // return x-axis coordinate
     int Ycoord() const;         // return y-axis coordinate
     int isSameAs(const Location& other) const; 
                                        // are two locations the same
   };
   // the implementation follows

    Location::Location( int x, int y ) { currentX = x; currentY = y; }

    Location::Location () { currentX = -1; currentY = -1; }

int Location::Xcoord() const { return currentX; }
int Location::Ycoord() const { return currentY; }
int Location::isSameAs(const Location& other) const{
     if ((currentX == other.Xcoord()) &&
         (currentY == other.Ycoord()) )
          return 1;
     else return 0;
}



Notice again that the const modifier for the parameter appears in both the class definition and the implementation where the code for the method is given.

Notice also that the isSameAs() method is itself declared to be a const method because it does not change the object to which it is applied. Thus, it is possible to apply this method to constant Location objects as in the following example:

       const Location dialogLocation (200,200);        // application information

        ...

        Location someWhere();

        // manipulate someWhere...

        if (dialogLocation.isSameAs(someWhere)) {...}

Notice that the parameter object named someWhere need not be a constant object. The reference that the isSameAs method works with, however, is modified by const so that the isSameAs method may not change the parameter even if, as in this case, the parameter is not itself a constant object. In other words, for the purposes of this method invocation, the parameter is treated as if it was a constant object, whether it really is or not.

Using const with Pointers

The const modifier can be used in conjunction with a pointer in one of three ways, depending on whether the modifier applies to: the object being pointed to (lp1 in the figure below), the pointer to the object (lp2 in the figure below), or both the pointer and the object being pointed to (lp3 in the figure below). The placement of the const modifier varies in each case, and in the third case it appears twice. The three different uses of const with pointers is shown graphically in the figure below, then its code is given and explained.


Uses of const with Pointers

In the code, the declaration for lp1 specifies that the object being pointed to is constant, that is the object "loc" may not be changed when it is accessed via the lp1 pointer. In the example code, the use of lp1 to apply the Xcoord() method is legal but the use of lp1 to apply the setX() method would be illegal. Also, since lp1 itself is not constant, it can be made to point to another Location object (e.g., other). However, using lp1 it would not be possible to modify the other object.

The declaration of lp2 specifies that the pointer, but not the object, is constant. Thus, it is legal to apply methods that modify the object being pointed to by lp2. However, it is not legal to assign a new value to lp2 itself. The const in this case indicates that the pointer value is constant and cannot be changed to point to another object.

The declaration of lp3 specifies that both the pointer and the object are constant. Thus, const methods, like Xcoord(), can be applied to the object. However, the object cannot be changed by using mutator methods like setX() and the pointer itself cannot be changed to point to another object.

    Location loc(100,100);
     Location other(50,50);

     const Location *lp1        = &loc;  // object constant
     Location const *lp2        = &loc;  // pointer constant
     const Location * const lp3 = &loc;  // both constant

     lp1->Xcoord();                      // OK
     lp1->setX(10);                      // ERROR
     lp1 = &other;                       // OK

     lp2->Xcoord();                      // OK
     lp2->setX(10);                      // OK
     lp2 = &other;                       // ERROR

     lp3->Xcoord();                      // OK
     lp3->setX(10);                      // ERROR
     lp3 = &other;                       // ERROR


A final variation of the Location class, is presented in the following figure, illustrates the use of const and pointers for parameters. In this example, the isInList() method is added, which determines if the coordinates of the object also appear in an array of Location objects passed as a parameter. The declaration of the parameter in the isInList method specifies that both the pointer and the array being pointed to cannot be changed by the execution of the method. Also, the isInList method itself is declared to be const, meaning that it cannot change the data of the object performing the method (i.e., the object searching the list for its coordinates).


Constant Pointers in the Location Class
 class Location {                         // Extension 3
   private:

     int  currentX, currentY;

   public:

        Location(int x, int y);         // specific location
        Location();                     // default location
     int Xcoord() const;                // return x-axis coordinate
     int Ycoord() const;                // return y-axis coordinate
     int isInList(const Location * const list) const; 
                                        // check if this object is in list
   };
   // the implementation follows

    Location::Location( int x, int y ) { currentX = x; currentY = y; }

    Location::Location () { currentX = -1; currentY = -1; }

int Location::Xcoord() const { return currentX; }
int Location::Ycoord() const { return currentY; }
int Location::isInList(const Location * const list, const int
length) const const int length
{
  for( int i = 0; i<length; i++)
     if( (currentX == list[i].Xcoord()) &&
         (currentY == list[i].Ycoord()) )
       return 1;
  return 0;
}



To complete the above example, here is the code that uses the isInList method.

  Location finder(100,100);

   Location list[10];
   int length = 10;

   //...give values to objects in array list

   if (finder.isInList(list, 10))
        { finder's coordinates are in the list }
   else { finder's coordinates are not in the list }

In this code, the array of Location objects is passed as a pointer consistent with the C language form of passing arrays.

 

Tasks

  1. Write the declaration of a constant Location object that specifies the center position on a 800 x 600 display.
  2. Rewrite the declaration of the Shape class to include the use of const.
  3. Examine the interface of the Frame class and identify all of the parameters and methods that could be declared as constant parameters or constant methods.
  4. Examine the interface of the TextBox class and identify all of the parameters and methods that could be declared as constant parameters or constant methods.



©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement

 

 

 

ÿ