Type qualifiers : const , volatile , in C++ a tutorial

 

A declaration for an object in c++ has the following form :

[Storage class] [Qualifier] Type Name ;

/*brackets means optional  .*/

For storage classes you can check this tutorial , as for qualifiers , they are used to qualify a definition , as being either a constant definition : const , or a volatile definition : volatile , or both a const volatile definition .

const and volatile can be used with variables , functions parameters and return values , class types data members and function members .

const

const means immutable , no change is to be made for a definition , after a definition has been provided . A constant variable must be initialized .

An example with variables .

int var_i;
/*var_i is not a constant 
  variable , its definition 
  can be changed .*/
var_i = 1; 

int var1_i;
/*var1_i  is not a constant 
  variable , its definition can 
  be changed .*/
var1_i = 1; 

const int var_ci = -1 ;
/*var_ci  is a constant 
  variable , its definition 
  cannot change . 
  var_ci can also be declared 
  int const var_ci = -1 ; */

int const *ptr_ci = &var_i;
/*ptr_ci is a pointer to 
  a constant integer , 
  it is illegal to use
  *ptr_ci = 4 ; 
  to change the value of 
  the pointed to integer .*/

int *const cptr_i = &var_i;
/*cptr_i is a constant pointer
  to an integer . The value 
  of cptr_i cannot be changed .
  It is illegal to do :
  cptr_i = &var1_i; .*/

const int *const cptr_ci = &var_i;
/*cptr_ci is a constant pointer 
  to a constant integer . The
  value of the pointer and the 
  pointed value cannot be changed .
  It is illegal to do :
  cptr_ci = &var1_i;
  *cptr_ci = 34; .*/

An example with function parameters .

const int * foo(const int *ptr_ci ){
  /*ptr_ci is a pointer to a
    constant integer , the value
    of the constant integer must
    not be changed .
    The function foo , perform
    an operation , that does not
    affect original data .*/

  static int arr_i[ ] =	{0 , 1 , 2 , 3 };
  /*Declare a static array arr_i.*/

  return &arr_i[1];
  /*Return the address of the
    second element of the array .*/ }

An example with class data members , and class member functions .

class Foo{
public:
  const int var_i;
  float var_f;
  mutable double var_d;
  /*A mutable class data member ,
    can be changed , even
    if its class instance is
    declared constant .*/
  Foo( );
  void cFct( )const; };

Foo::Foo():var_i(0 ) , var_f(-1.f ) , var_d(0.4 ){}

void Foo::cFct( )const{
  /*A constant function can access
    all data members , but must not
    change the value of any , beside
    a data member which is declared
    mutable .*/
  var_d = var_d + var_f + var_i; }

int main(void ){
  Foo foo;
  /*Create an object named foo ,
    It is illegal to do
    foo.var_i = -1 ; 
    because var_i is declared
    constant .*/

  foo.var_d = foo.var_i + foo.var_f + foo.var_d ;
  /*Assign a value to var_d .*/

  foo.cFct();
  /*Call the constant function cFct .*/


  const Foo foo_c;
  /*Create an object named foo_c.
    foo_c is declared constant ,
    it is allowed only to change
    the value of a mutable data
    member.
    It is illegal to do :
      foo_c.var_f = 4.f ; .*/

  foo_c.var_d = foo.var_i + foo.var_f + foo.var_d ;
  /*Assign a value to var_d , which is
   a mutable data member .*/
  foo_c.cFct();
  /*A constant object is only 
    allowed to call constant 
    functions .*/ }

volatile

A volatile qualifier , is used to inform the compiler , that a variable definition , can change asynchronously to the program . So in a way , which is not related to a change made by the program itself , hence the change to the variable can be made by an external process .

When the volatile qualifier is used , the compiler is not to do certain optimization , that relies on the fact that a change in a variable definition , is synchronous to the program itself . When a variable is accessed , and even if the program itself did not change its value , the value of the variable is to be reread .

member functions which are not static , can be declared volatile , If an instance of a class is volatile , it can only access volatile member functions .

class Foo{
public:
  volatile int var_vi;
  float var_f;
  Foo();
  void fct_v( )volatile;
  void fct();
};

Foo::Foo( ):var_vi(1 ) , var_f(-3.f ){}

void Foo::fct_v( )volatile{
  var_vi = var_vi + var_f; }

void Foo::fct( ){
  var_vi = var_vi + var_f; }


int main(void ){
  Foo foo;
  /*Create an instance of foo .*/
  foo.var_vi = -1;
  /*Set a value to the volatile
    data member .*/
  foo.fct_v();
  /*Call the volatile function .*/
  foo.fct();
  /*Call the non volatile function .*/

  volatile Foo foo_v;
  /*Create a volatile instance of
    Foo .
    Each data member of foo_v
    is volatile . foo_v can
    only access functions declared
    as volatile .*/
  foo_v.var_f = 3.1f;
  /*Set a value to var_f which 
    is not declared volatile .*/
  foo_v.fct_v(); 
  /*Call the volatile function 
    fct_v .*/ }

const can be used with volatile , to indicate the constance of a variable with regards to the program itself , but the ability of this variable of being changed from outside the program .

const volatile int var_ci = 0 ;