The const Keyword in Function Declaration of Classes in C++
-
the
const
Keyword in Function Declaration of Classes in C++ - the Behavior of a Member Function in C++
-
the Behavior of a
const
Member Function in C++ - Conclusion
In C++, the const
keyword defines those values that will not change and remain constant during the program execution. This sounds pretty simple for variables and the data they hold.
But, how can a function be declared constant, and what needs to be kept unchanged in a function? We will answer all these questions and much more in this article, so keep reading!
Note that the functions that we are looking at here are the ones that belong to a class, that is, member functions.
the const
Keyword in Function Declaration of Classes in C++
Before diving into the actual discussion, let us understand the problem statement correctly.
We already know that a class can have data members and member functions. These member functions are usually declared inside the class as follows -
class Demo // class
{
public:
int x;
int showDemo(); // member function declaration
}
Here, the member function showDemo()
belongs to the class Demo
. But what does it mean if we add const
at the end of the member function like this -
class Demo // class
{
public:
int x;
int showDemo() const; // const member function declaration
}
Let us first see how a member function normally behaves in C++ to understand this.
the Behavior of a Member Function in C++
Look at the code given below. Here, we first define a class called Demo
with a data member, chocolates
, whose value is set to 2,
and a member function, Desert()
.
Inside the member function, along with a welcome statement, we print the original value of the data member, chocolates
, and then increment this value by one. Further, we print the incremented value of chocolates
in the next statement.
Finally, we create an object, demo
, and call the member function Desert()
from the main
block. Also, we print the value of chocolates
using the object demo
and dot
operator.
#include <iostream>
using namespace std;
class Demo {
public:
int chocolates = 2;
public:
void Desert() // member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
Output:
Hello Chocolates
Before change: 2
After change: 3
3
You can see that here, we changed the value of the data member, chocolates
, from inside the member function. To emphasize the change more precisely, we print the value of this variable from the main
block as well, but we still get the updated value, which is 3
.
This example thus implies that we can somehow use a normal member function to change the object.
Here, we have only one class and one object. However, while working with many classes and objects, there are high chances that changes are accidentally made to an object.
To avoid this, we use the const
member function of C++.
the Behavior of a const
Member Function in C++
Look at the example given below. This code is the same as the previous one, except that we put the const
keyword after the member function this time.
#include <iostream>
using namespace std;
class Demo {
public:
int chocolates = 2;
public:
void Desert() const // const member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
Output:
In member function 'void Demo::Desert() const':
error: increment of member 'Demo::chocolates' in read-only object
13 | chocolates++;
| ^~~~~~~~~~
You can see how the output changes by making the member function a constant. This time, the value of chocolates
is not incremented, and we get an error.
This example thus implies that we cannot use a const
member function to change the object in any way.
By the above two comparisons of member functions, we conclude that the use of const
in such function declarations implies that there won’t be any change in any class member. When we add const
to a method, the this
pointer points to the const
object, and thus, we cannot change any data member.
After all that we have learned, we can say that we use the const
member functions to avoid changing an object. But then, you might wonder: what is the use of a const
object?
When we declare an object as const
, it can invoke only the const
member functions. This is because a const
object cannot be modified, and this non-alteration is only promised by const
member functions.
Look at the example below.
Inside the Desert
class, we have two member functions, desert()
and desert() const
. Then, inside the main
block, we define two objects, d
, and a constant object, dd
.
Note some important points about this example:
- We have two member functions with the same name. The only difference is that one of them is a
const
member function. - We have two objects, one of which is a constant object.
- We call the member function
desert()
from both the objects without specifying which object calls which function.
#include <iostream>
using namespace std;
class Desert {
private:
int cakes;
public:
void desert() { cout << "The first desert function." << endl; }
void desert() const // the const member function
{
cout << "The second const desert function." << endl;
}
};
int main() {
Desert d; // object of class
const Desert& dd = d; // constant object of class
d.desert();
dd.desert();
}
Output:
The first desert function.
The second const desert function.
The output clearly shows that the normal member function, desert()
, was automatically called by the normal object, d
. While, the const
member function, desert() const
, is automatically invoked by the const
object, dd
.
The output will change if we remove the const
keyword from the object.
int main() {
Desert d; // object of class
Desert& dd = d; // remove the constant keyword
d.desert();
dd.desert();
}
Output:
The first desert function.
The first desert function.
This time both the objects call the first function. This proves that a const
object invokes a const
member function.
Note that this does not mean we cannot call a const
member function on a non-constant object. However, a non-const
function can only be called by non-const
objects.
So far, so good, but there is an exceptional case. If we use the mutable
quantifier with any data member of the class, we can modify the object even in a const
method.
Look at this example.
#include <iostream>
using namespace std;
class Demo {
public:
mutable int chocolates = 2; // mutable quantifier
public:
void Desert() const // const member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
Output:
Hello Chocolates
Before change: 2
After change: 3
3
Now this time, we do not get an error like before because we are using the mutable
quantifier with the data member chocolates
. This is often helpful if we want to count the number of times a method is called.
This is all about a const
member function in C++. The more you play with the examples, making little changes here and there, the more clarity you will gain!
To know more about const
in C++, refer to this documentation.
Conclusion
In this article, we discussed the concepts of const
member functions of C++. A const
member function ensures that an object is not accidentally modified, and we can use it with both const
and non-const
objects.
However, a const
object can only revoke a const
member function. Also, using the mutable keyword with the data members can change the usual behavior of the const
member function and is usually used for counting purposes.