Previous      Up      Previous     Course Home   e-mail

2.19 Why do many functions come in pairs that are nearly identical except for a const?


class Point {
int xcoord ;
int ycoord ;
public :
Point ( int x , int y ) :
xcoord ( x ), yxoord ( y )
{}

int & x () { return xcoord ;}
int & y () { return ycoord ;}
};
Let’s suppose that we have a simple ADT: Note that, because the x() and y() functions return a reference (an address), we can both look at and assign to the components of a point:

aPoint . x () = aPoint . y ();

void foo ( Point & p1 , const Point & p2 )
{
cout << " ( " << p1 . x () <<
" , " << p1 . y () << " ) " << endl ;
p1 . x () = 14;

cout << " ( " << p2 . x () <<
" , " << p2 . y () << " ) " << endl ;
p2 . x () = 14;
Now suppose that we try to use our ADT in a function. This code has a real error in it. We have received p2 as a const reference. That means that foo promises not to do anything to p2 that would change its value. The final assignment statment clearly attpents to change p2. Obviously the programmer is confused and has forgotten that promise. When we compile this function, we would get error messages from the compiler on all our uses of p2 (not just on the assignment). Why? Because foo promises not to do anything to p2 that would change its value, and the compiler is going to enforce that promise. Obviously the assignment of 14 to p2.x() breaks that promise. But, in general, the compiler has no way of knowing that any call to x() or y() would not change the Point they were applied to. The fact that the current bodies of those don’t make any such changes is irrelevant - the designer of the Point ADT could come along and change those at any time. So the compiler will not permit us to apply any function to p2 that does not promise to leave p2 unchanged.

How does a member function promise to leave its object unchanged? By having the word const after the parameter list.

So we could change our ADT as shown here, which would allow our foo function to compile.

class Point {
  int xcoord;
  int ycoord;
public:
  Point (int x, int y) :
    xcoord(x), yxoord(y)
  {}

  int& x() const {return xcoord;}
  int& y() const {return ycoord;}
};

But we’re really lying to the compiler here. We are saying that these two functions are safe to use with a value we don’t want changed. The simple fact that we can usethem to write


p2 . x () = 14;
shows this to be a lie.

With this change

class Point {
  int xcoord;
  int ycoord;
public:
  Point (int x, int y) :
    xcoord(x), yxoord(y)
  {}

  int x() const {return xcoord;}
  int y() const {return ycoord;}
};
We can live up to our promise by changing the output type:but now when we compile

void foo ( Point & p1 , const Point & p2 )
{
cout << " ( " << p1 . x () <<
" , " << p1 . y () << " ) " << endl ;
p1 . x () = 14;

cout << " ( " << p2 . x () <<
" , " << p2 . y () << " ) " << endl ;
p2 . x () = 14;
both assignments get flagged with errors. That’s OK for the assignment to p2, which we should not be allowed to do (since p2 is declared as const) but there’s no logical reason to forbid this operation on the non-const p1.

We get the best of both worlds be including both the const and the original non-const forms of these functions:

class Point {
  int xcoord;
  int ycoord;
public:
  Point (int x, int y) :
    xcoord(x), yxoord(y)
  {}

  int& x() {return xcoord;}
  int x() const {return xcoord;}


  int& y() {return ycoord;}
  const int& y() const {return ycoord;}
};

Now when we compile


void foo ( Point & p1 , const Point & p2 )
{
cout << " ( " << p1 . x () <<
" , " << p1 . y () << " ) " << endl ;
p1 . x () = 14;

cout << " ( " << p2 . x () <<
" , " << p2 . y () << " ) " << endl ;
p2 . x () = 14;
the compiler chooses, for each call to x() and y() the “best fitting” version of the function. When applied to the non-const p1, the compiler uses the non-const versions of x() and y(). When applied to the const p2, the the compiler uses the const versions of x() and y(). That menas that only the line with assignment to p2gets flagged, as is appropriate.

 Previous      Up      Previous     Course Home   e-mail