Introduction
This article talks about all different usage of const qualifier in C++.
Background
Declaration:
Named constant or const variables
const int PI = 3.14
Declares a named constant called PI, which can be used later in the program where ever we want to use the value 3.14.
This is similar to #define macro, but using const is better as it is understood and used by the compiler itself and not just simple substitution in the program which is done by preprocessor on using #define.
const with pointers:
Here one has to be careful in using const to know whether it is used to determine the
- Pointer as constant or
- The Data what it points is constant or
- Both i.e. both Data and Pointer are constant.
To declare a pointer that is pointing to a constant interger
const int *ptrToConstData1;
int const *ptrToConstData2;
Here, we cannot change the data it is pointing to.
To declare a const pointer that is pointing to an integer
int * const ptrIsConst;
This has to be declared and initialised and cannot be changed later to point to some other variable.
To declare a const pointer pointing to constant integer
const int * const ptrAndDataCnst;
Here both pointer and data are constant. As it is also a constant pointer, it has to be initialised while declaring itself.
The code
Code: Cpp
#include<iostream.h>
int main()
{
//declaring a named constant
const float PI = 3.14;
cout<<"PI Value is: "<<PI;
cout<<endl;
//pointer to constant integer
int i = 123;
int const *ptrToConstData;
ptrToConstData = &i;
cout<<*ptrToConstData;
//cant change as it is pointing to const value
//*ptrToConstData = 321;
//
//constant pointer
int j = 123;
int * const ptrIsConst = &j;
cout<<endl;
cout<<*ptrIsConst;
//cant change as it is a const pointer
//ptrIsConst = &i;
//constant pointer pointing to constant integer
int k = 123;
const int * const ptrAndDataConst = &k;
cout<<endl;
cout<<*ptrAndDataConst;
cout<<endl;
return(0);
}
output:
-----------
PI Value is: 3.14
123
123
123
const Data Member:
Any const data members of a class has to be initialized and has to be done in the initilizer list of the class's constructor. Only static const data members can be intialized inside the class declaration.
The code
Code: Cpp
#include<iostream.h>
class Abc
{
const int myInt_m;
static const double myDouble_m = 100.53;
public:
//We cannt initialise the const members inside the constructor as below
/*Abc(int j=0)
{
myInt_m = j;
cout<<"Value of myInt is : "<<myInt_m<<endl;
}*/
//we have to initialise it in initializer list as below
Abc(int j =0):myInt_m(j)
{
cout<<"Value of myInt_m is : "<<myInt_m<<endl;
cout<<"Value of myDouble_m is : "<<myDouble_m<<endl;
}
};
int main()
{
Abc abc(10);
return(0);
}
output:
----------
Value of myInt_m is : 10
Value of myDouble_m is : 100.53
Return by const value:
Return by const is meaningful in case of returning:-
- const strings and arrays from functions as they are implemented as pointers. This is to avoid the program altering their lValue and getting crash.
- If a function is returning any user-defined data types like class objects. Where as It does not make sense returning const to a built-in types, as compiler anyway takes care of it.
In above cases by making that function returning a const will prevent using that returned value as an lValue in program as it will be a compier error. Otherwise, it will allow using that returned value as lValue.
The code
Code: Cpp
#include <iostream.h>
char* func1()
{
return ("Mridula");
}
const char * func2()
{
return ("Mridula");
}
int func3()
{
return (1);
}
class Abc
{
int myInt;
public:
Abc(int j=0):myInt(j)
{
cout<<"Value of myInt is :"<<myInt<<endl;
};
};
Abc func4()
{
return Abc();
}
const Abc func5()
{
return Abc();
}
int main()
{
//Trying to modify will lead to segmentation fault
//Func1()[1] = 'K';
//Trying to modify will give a compiler error now
//Func2()[1] = 'K';
//Compiler will anyway prevent using it as an lValue here as it is built-in data type
//func3() = 3;
//Compiler will allow using func4 as lValue
func4() = Abc(5);
//Compiler will prevent using func5 as lValue now
//func5() = Abc(10);
return (0);
}
output:
---------
Value of myInt is :0
Value of myInt is :5
const variable as an argument:
To make sure, preventing the data that is passed as argument, whether it could be a reference or pointer variable (which was sent to avoid sending by value as copying in case of big user defined data is costly), getting aletred inside the function or callee, then we can send that data by const qualifier.
The code
Code: Cpp
#include<iostream.h>
void func1(int &j)
{
//function is modifying it
j = 100;
cout<<j;
cout<<endl;
}
void func2(int const &j)
{
//cant modify the value, compiler error
//j= 10;
cout<<j;
cout<<endl;
}
void func3(int j)
{
//declare a reference to int and reference to the sent data
const int &k = j;
//altering this value would be a compiler error
//k = 10;
cout<<j;
cout<<endl;
}
int main()
{
int k;
k= 10;
func1(k);
k=20;
func2(k);
k=30;
func3(k);
return (0);
}
output:
---------
100
20
30
As shown in the example, to ease the burden of caller not sending data as const, we can even implement inside the function by making a const reference to the sent value and then prevent alering it.
const Member Functions:
Declaring as below makes that method as const
int myInt() const
it means, function is not allowed to modify any of the data members of that class object. Normally, get accessors are written as const methods.
The code
Code: Cpp
#include<iostream.h>
class Abc
{
int myInt_m;
int k;
public:
Abc(int j=0):myInt_m(j)
{
cout <<j;
cout<<endl;
}
int myInt() const
{
//trying to modify this will lead to compiler error
//myInt_m = 20;
cout<<myInt_m;
cout<<endl;
return(myInt_m); //---
}
};
int main()
{
int k;
Abc abc(100);
k = abc.myInt();
return(0);
}
output:
--------
100
100
const int*const myFunction(const int*const&)const
This one is an example of a const method, that will return a constant pointer, pointing to a const integer, also it does not alter any of passed arguments to it.
Related terms to const
operator const_cast < >
This is used to remove the constant quality of a variable or object.
The code
Code: Cpp
#include<iostream.h>
void sqrtVal(const int* a)
{
int * j = const_cast<int *> (a); //cast away const-ness
*j = (*j)*(*j);
cout<<"sqrtVal :"<<*j<<endl;
}
int main()
{
cout<<"Case 1: where Integer variable is not explicitlly associated with const"<<endl;
int a = 10;
cout<<"Before the value of a :"<<a<<endl;
const int *k = &a;
sqrtVal(k);
cout<<"After the value of a :"<<a<<endl<<endl;
cout<<"Case 2: where Integer variable is explicitly associated with const"<<endl;
const int b=10;
cout<<"Before the value of a :"<<a<<endl;
const int *l = &b;
sqrtVal(l);
cout<<"After the value of a :"<<b<<endl<<endl;
return(0);
}
output:
----------
Case 1: where Integer variable is not explicitlly associated with const
Before the value of a :10
sqrtVal :100
After the value of a :100
Case 2: where Integer variable is explicitly associated with const
Before the value of a :100
sqrtVal :100
After the value of a :10
As shown in the above example, case-1 we can cast away the constness of a variable or object, that is not explicitly declared with const qualifier. Where as in case-2, if we try to cast away constness of a variable or object that has been explictly declared as const, results in undefined bahaviour.
Also, below is another example showing the usage of const_cast in a class's const member function.
The code
Code: Cpp
#include<iostream.h>
class Abc
{
int myInt_m;
public:
Abc(int j=0):myInt_m(j)
{
}
void modifyConstFunc(void) const
{
cout<<"Initial value of myInt_m: "<<myInt_m<<endl;
//try to modify myInt_m
const_cast <Abc *> (this)->myInt_m--;
cout<<"Modified value of myInt_m :"<<myInt_m<<endl;
}
};
int main()
{
Abc abc(10);
abc.modifyConstFunc();
return(0);
}
output:
--------
./a.out
Initial value of myInt_m: 10
Modified value of myInt_m :9
Here, in this example, const_cast allows to modify the member of a class in a constant member function.
mutable keyword
Declaring a member variable as mutable allows that particular variable to be modified in a const member function. It means, it allows the declared member of a constant object to be modified.
This concept is used, when most of the data members of a class are kept const, but few need to be updatable, then declare those updatable members as mutable.
The code
Code: Cpp
#include<iostream.h>
class Employee
{
const int myId_m;
const char *myName_m;
mutable double mySalary_m;
public:
Employee(const int id,
const char* name,
double salary):
myId_m(id),
myName_m(name),
mySalary_m(salary)
{
cout<<"Employee details ..."<<endl;
cout<<"------------------------"<<endl;
cout<<"Id: "<<myId_m<<endl;
cout<<"Name: "<<myName_m<<endl;
cout<<"Salary: "<<mySalary_m<<endl;
cout<<endl;
};
const int getMyId(void) const
{
return (myId_m); //---
}
const char *getmyName(void) const
{
return(myName_m); //---
}
double getSalary(void) const
{
return(mySalary_m);
}
void increment(int id, double salary) const
{
//confirm the id and update the salary
if (id == myId_m)
{
mySalary_m += salary;
}
}
};
int main()
{
Employee emp(10, "Mridula", 10000);
emp.increment(10, 5000);
cout<<"Updated salary :"<<emp.getSalary()<<endl<<endl;
return(0);
}
output:
----------
Employee details ...
------------------------
Id: 10
Name: Mridula
Salary: 10000
Updated salary :15000
References
Also Refer:
Constant and pointer
http://www.go4expert.com/showthread.php?t=1578



