Just like with fundamental types, program-defined types can be labelled const. In doing so, the members become immutable.
const applies to the whole object
Consider this struct:
struct DeviceConfig {
int sampleRateHz {};
int uploadIntervalMinutes {};
bool lowPowerMode {};
};
We can create a const instance:
#include <iostream>
struct DeviceConfig {
int sampleRateHz {};
int uploadIntervalMinutes {};
bool lowPowerMode {};
};
int main(){
const DeviceConfig config {
.sampleRateHz = 1000,
.uploadIntervalMinutes = 15,
.lowPowerMode = true
};
std::cout << "Sample rate: " << config.sampleRateHz << " Hz\\n";
std::cout << "Upload interval: "
<< config.uploadIntervalMinutes << " minutes\\n";
std::cout << "Low power mode: " << config.lowPowerMode << '\\n';
// config.sampleRateHz = 2000; // ERROR: config is const
}
Terminal output:
Sample rate: 1000 Hz
Upload interval: 15 minutes
Low power mode: 1
Despite sampleRateHz not being const it still has the attribute of immutability since it belong to a const struct instance.
const objects cannot call non-const member functions
Now suppose the struct has a member function:
#include <iostream>
struct Date
{
int year {};
int month {};
int day {};
void print() // Non-const
{
std::cout << year << '/' << month << '/' << day;
}
};
int main()
{
const Date today { 2020, 10, 14 }; // const
today.print(); // ERROR
}
/tmp/PCba1kv8Zv/main.cpp:19:16: error: passing 'const Date' as 'this'
argument discards qualifiers [-fpermissive]
19 | today.print(); // ERROR
The call fails because print() is not marked const.
From the compiler’s perspective, a non-const member function may modify the object. Since config is const, the compiler does not allow the call.
Luckily, there is an easy fix. We can make the method const by typing it after the parameter list, but before the function body.
void print() const { ... }
2020/10/14
const member functions may be called by non-const objects
You cannot have a const class instance call a non-const method. However, the opposite is legal. A non-const class is permitted to call a const method
#include <iostream>
struct DeviceConfig {
int sampleRateHz {};
int uploadIntervalMinutes {};
bool lowPowerMode {};
void print() const
{
std::cout << "Sample rate: " << sampleRateHz << " Hz\\n";
std::cout << "Upload interval: "
<< uploadIntervalMinutes << " minutes\\n";
std::cout << "Low power mode: " << lowPowerMode << '\\n';
}
};
int main()
{
DeviceConfig config {
.sampleRateHz = 500,
.uploadIntervalMinutes = 30,
.lowPowerMode = false
};
config.print();
}
Terminal output:
Sample rate: 500 Hz
Upload interval: 30 minutes
Low power mode: 0
Since the method is const, it promises not to modify the members. As a result, the compiler trusts it and permits it to operate on const and non-const struct instances.
A good rule of thumb is to label methods as const if the method only needs read-only access.
Summary
- A
conststruct object makes its members read-only through that object. - A
constobject cannot call a non-const member function. - A
constmember function can be called by both const and non-const objects.