The const modifier

(simple use)


  const  type  id = value;

For example:

  const double PI = 3.1415;

Syntax also permits (exact same effect):

  type  const  id = value;

const and pointers

  int x = 16;
  const int * p = &x;

"p points to a const int"

So . . .

  *p = expr;    // NOT ALLOWED
  cin >> *p;    // NOT ALLOWED

  x++;   // OK. x is not constant!


  const double Y = 3.23;
  const double * pY = &Y;

This is OK, because
a pointer-to-const points to a const.



  // NOT ALLOWED !
  const double Y = 3.23;
  double * pY = &Y;

This is not allowed, because
we could "cheat," doing:

  *pY = 1.6;

If we did this, then it subverts the declaration
of Y as a constant.

Essentially, the implementation of a const
modifier becomes unenforceable.


#include <iostream>
using namespace std;

int main() {
  const int X = 2;
  int * ptrX = &X;

  cout << "X = " << X << endl;
  cout << "*ptrX = " << *ptrX << endl;

  *ptrX = 3;  // subverts const declaration
  cout << "now, X = " << X << endl;
  cout << "now, *ptrX = " << *ptrX << endl;

  return 0;
}

Gives compilation error:

const4.cpp: In function `int main()':
const4.cpp:7: error: invalid conversion 
from `const int*' to `int*'

The pointer variable is the const

  int intvar;
  int * const ptr = &intvar;

Syntax locates the const modifier
between the * and the identifier.

  int intvar2;
  ptr = &intvar2;

gives compiler error:

assignment of read-only variable `ptr'

References

References

  int name1 = 5;
  int & name2 = name1;

  int name3 = 6;
  name2 = name3;

  cout << name1 << " " << name2 << " " 
       << name3 << endl;

Conclusion: set a reference by an initializing
declaration. Assignment does not usually
do what you want.


Call by Value

C and C++ use call by value arguments

  void foo(int fooX);  // prototype

  int main() {
     int X = 3;
     foo(X);           // call
  }
  void foo(int fooX) { // definition
  }

main creates variable X, and assigns it the value 3.

foo creates variable fooX,
and assigns it the passed value 3.

fooX disappears upon return from foo.


Call by Reference functionality

C and C++ use call by value arguments,
but need the functionality of call by reference,
so, pass a pointer. . .

  void bar(int *barX);  // prototype

  int main() {
     int X = 3;
     bar(&X);           // call
  }
  void bar(int *barX) { // definition
     *barX = 4;
  }

main creates variable X, and assigns it the value 3.

bar creates pointer-to-int variable barX,
and assigns it the passed value (the address of X).

bar uses the pointer to change X.

barX disappears upon return from bar.


Call by Reference

(References as Arguments)

C++ has call by reference arguments

  void pip(int & pipX);  // prototype

  int main() {
     int X = 3;
     pip(X);           // call
  }
  void pip(int & pipX) { // definition
     pipX = 4;
  }

main creates variable X, and assigns it the value 3.

pip makes pipX a reference for variable X.

pipX is assigned the value 4.
(X changes, as pipX is a reference for X.)

pipX (the alias) disappears upon return from pip.


be aware of the (context) use of &


mixing references and the const modifier

An example to show a difficulty:

 int cube(int A);  // prototype
 int refcube(int & A);  // prototype

 int main() {
    int X = 3;
    cout << cube(X);
    cout << "is cube of " << X << endl;
    cout << refcube(X);
    cout << "is cube of " << X << endl;
 }

 int cube(int A) { // definition
    A = A * A * A;
    return A;
 }

 int refcube(int & A) { // definition
    A = A * A * A;
    return A;
 }

force function not to change A:

  int refcube(const int & A);  // prototype

  int refcube(const int & A) { // definition
     A = A * A * A;
     return A;
  }

Compiler error, since we attempt to change A


force the use of a temporary variable:

  int refcube(const int & A);  // prototype

  int refcube(const int & A) { // definition
     return  (A * A * A);
  }

Another case where the compiler generates
a temporary variable:

  int Y = 4;
  int Z = refcube(Y + 12);

See in-class handout with advice on when to use:


Default arguments

 // prototype
 int flex(int x, int y = 10, char z = 'a');

 // definition
 int flex(int x, int y, char z){
 }

 // calls
 i = flex(6, 7, 'b');
 j = flex(6, 7);  // z is 'a'
 k = flex(6);     // y is 10, z is 'a'
 m = flex();      // compiler error:
                  //   too few arguments

Copyright © Karen Miller, 2007