In the lesson on passing arguments by reference, we covered the merits of passing function parameters as const variables. To recap, making variables const ensures their values are not accidentally changed. This is particularly important when passing variables by reference, as callers generally will not expect the values they pass to a function to be changed.
Just like the built-in data types (int, double, char, etc…), class objects can be made const by using the const keyword. All const variables must be initialized at time of creation. In the case of built-in data types, initilization is done through explicit or implicit assignment:
1 2 |
const int nValue = 5; // initialize explicitly const int nValue2(7); // initialize implictly |
In the case of classes, this initialization is done via constructors:
1 2 |
const Date cDate; // initialize using default constructor const Date cDate2(10, 16, 2020); // initialize using parameterized constructor |
If a class is not initialized using a parameterized constructor, a public default constructor must be provided -- if no public default constructor is provided in this case, a compiler error will occur.
Once a const class object has been initialized via constructor, any attempt to modify the member variables of the object is disallowed, as it would violate the constness of the object. This includes both changing member variables directly (if they are public), or calling member functions that sets the value of member variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Something { public: int m_nValue; Something() { m_nValue = 0; } void ResetValue() { m_nValue = 0; } void SetValue(int nValue) { m_nValue = nValue; } int GetValue() { return m_nValue; } }; int main() { const Something cSomething; // calls default constructor cSomething.m_nValue = 5; // violates const cSomething.ResetValue(); // violates const cSomething.SetValue(5); // violates const return 0; } |
All three of the above lines involving cSomething are illegal because they violate the constness of cSomething by attempting to change a member variable or calling a member function that attempts to change a member variable.
Now, consider the following call:
1 |
std::cout << cSomething.GetValue(); |
Surprisingly, this will cause a compile error! This is because const class objects can only call const member functions, GetValue() has not been marked as a const member function. A const member function is a member function that guarantees it will not change any class variables or call any non-const member functions.
To make GetValue() a const member function, we simply append the const keyword to the function prototype:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Something { public: int m_nValue; Something() { m_nValue = 0; } void ResetValue() { m_nValue = 0; } void SetValue(int nValue) { m_nValue = nValue; } int GetValue() const { return m_nValue; } }; |
Now GetValue() has been made a const member function, which means we can call it on any const objects.
Const member functions declared outside the class definition must specify the const keyword on both the function prototype in the class definition and on the function prototype in the code file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Something { public: int m_nValue; Something() { m_nValue = 0; } void ResetValue() { m_nValue = 0; } void SetValue(int nValue) { m_nValue = nValue; } int GetValue() const; }; int Something::GetValue() const { return m_nValue; } |
Any const member function that attempts to change a member variable or call a non-const member function will cause a compiler error to occur. For example:
1 2 3 4 5 6 7 |
class Something { public: int m_nValue; void ResetValue() const { m_nValue = 0; } }; |
In this example, ResetValue() has been marked as a const member function, but it attempts to change m_nValue. This will cause a compiler error.
Note that constructors should not be marked as const. This is because const objects should initialize their member variables, and a const constructor would not be able to do so.
Finally, although it is not done very often, it is possible to overload a function in such a way to have a const and non-const version of the same function:
1 2 3 4 5 6 7 8 |
class Something { public: int m_nValue; const int& GetValue() const { return m_nValue; } int GetValue() { return m_nValue; } }; |
The const version of the function will be called on any const objects, and the non-const version will be called on any non-const objects:
1 2 3 4 5 |
Something cSomething; cSomething.GetValue(); // calls non-const GetValue(); const Something cSomething2; cSomething2.GetValue(); // calls const GetValue(); |
Overloading a function with a const and non-const version is typically done when the return value needs to differ in constness. In the example above, the const version of GetValue() returns a const reference, whereas the non-const version returns a non-const reference.
Let’s take a look at making our date class member functions const so they can be used with const Date objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Date { private: int m_nMonth; int m_nDay; int m_nYear; Date() { } // private default constructor public: Date(int nMonth, int nDay, int nYear) { SetDate(nMonth, nDay, nYear); } void SetDate(int nMonth, int nDay, int nYear) { m_nMonth = nMonth; m_nDay = nDay; m_nYear = nYear; } int GetMonth() { return m_nMonth; } int GetDay() { return m_nDay; } int GetYear() { return m_nYear; } }; |
The only non-constructor member functions that do not modify member variables (or call functions that modify member variables) are the access functions. Consequently, they should be made const. Here is the const version of our Date class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Date { private: int m_nMonth; int m_nDay; int m_nYear; Date() { } // private default constructor public: Date(int nMonth, int nDay, int nYear) { SetDate(nMonth, nDay, nYear); } void SetDate(int nMonth, int nDay, int nYear) { m_nMonth = nMonth; m_nDay = nDay; m_nYear = nYear; } int GetMonth() const { return m_nMonth; } int GetDay() const { return m_nDay; } int GetYear() const { return m_nYear; } }; |
The following is now valid code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void PrintDate(const Date &cDate) { // although cDate is const, we can call const member functions std::cout << cDate.GetMonth() << "/" << cDate.GetDay() << "/" << cDate.GetYear() << std::endl; } int main() { const Date cDate(10, 16, 2020); PrintDate(cDate); return 0; } |
![]() |
![]() |
![]() |
const class objects can only call const member functions
Note: that constructors should not be marked as const. This is because const objects should initialize their member variables, and a const constructor would not be able to do so.
I think the above lines contradict each other. Please explain.
Hi,
I am passing a class object by refernce into a function which r eturns a class object
I have a header file, client cpp file and main file.
header:
class MFRACTION
{
public:
void set(int numer, int denom);
double toDouble() const;
QString toString() const;
MFRACTION add(const MFRACTION& );
MFRACTION (const MFRACTION& frr);
// MFRACTION & operator=(const MFRACTION other);
~MFRACTION ();
private:
int n;
int d;
MFRACTION.CPP:
void MFRACTION::set(int numer, int denom){
n = numer;
d = denom;
}
MFRACTION::MFRACTION(const MFRACTION &frr):n(frr.n),d(frr.d){}
double MFRACTION::toDouble()const{
return 1.0 * n/d;
}
QString MFRACTION::toString()const
{
return QString("%1/%2").arg(n).arg(d);
}
MFRACTION add(const MFRACTION&)
{
int n;
int d;
MFRACTION frr;
return MFRACTION ((n * frr.d)+ (d + frr.n),d*frr.n);
}
MAIN.CPP:
int main(){
MFRACTION f1, f2,f3;
QTextStream cout (stdout);
QTextStream cin(stdin);
int m;
f1.set(7,1);
f2.set(5, 8);
f3 = f1.add(f2);
cout << "The first fraction is" << f1.toString() << endl;
cout << "The second fraction is" << f2.toDouble() << endl;
cout<< "after calling"<< f3.toString()<> m;
return 0;
THE ERROR I M GETTING IS n.d and frr are private and not declared in this scope in the add function that i am calling in Mfraction.cpp file.
This program though written in Qt It uses all C++ coding.
Please help me what is wrong in this.
Mary
hi Alex,
I don't get how you have overloaded the functions, cause I remember you've said functions can be overloaded only if their signature (type/number of parameters) is diffrent which is not the case here
const int& GetValue() const { return m_nValue; }
int& GetValue() { return m_nValue; }
Hi Alex,
I strange thing about Const object:
lets say I have a class A, and no default or parameterised constructor. but in the main I try to create a const object of this.
const A a;
it does not throw any compilation error.
but if i do it for built in datatype like const int i, it tells us initialise at the time of creation.
Thanks,
Hi
Why do you set the return type of the GetValue() a reference in the below class?
I can not understant it, because m_nValue which GetValue() returns it, is not a reference.
class Something
{
public:
int m_nValue;
const int& GetValue() const { return m_nValue; }
int& GetValue() { return m_nValue; }
};
const and volatile specifier for the function definition is used for the function overload.
Alex,
It would be great if you could answer Anand's query since I also had the same doubt when I read the tutorial.
"Overloading the function doesn’t depend on Return type of function,
Overloading the function only depend on Signature of fucntion(i.e. no of args or types of args.)
Here Overloading function GetValue
const int& GetValue() const and
int& GetValue()
In this case, how does the compiler do name mangling?
Ahh... I almost gave in for the last part of this section.... Though confusing at the same time very simple explanation... may be for the first timers its little terrifying..
Hope i will come back to this section again :(