Summary
“const” declaration is one of the most messy features of C++. It is simple in conecpt: variables declared with ‘const’ added become constants and cannot be altered by the program. However it is also used to bodge in a substitute for one of the missing features of C++ and there it gets horridly complicated and sometimes frustratingly restictive.
- ‘const’ used on variables;
- ‘const’ used on reference;
- ‘const’ used on pointers;
- ‘const’ used on parameter passing and functions; ___
Part 1. ‘const’ used on variables
a) ‘const’ is a compile time constraint that an object cannot be modified;
b) ‘const’ declaration must be initialized.
const std::string hi = "hello"; // ok
const int i, j = 0; // error: i is not initialized
c) A non-const global variable is an ‘extern’ variable by defaults, while a const global variable has to be declared explicitly as ‘extern’.
// file_1.cc
extern const int bufSize = fcn();
// file_2.cc
extern const int bufSize; // use bufSize from file_1
Part 2. ‘const’ used on reference
a) A reference is an alias to a certain object and a reference has to be initialized and cannot redefined;
b) const reference is a reference to const variable and non-const reference cannot be initialized by a const variable;
const int ival = 1024;
const int &refVal = ival; // ok: a const reference
refVal += 2; // error: a const reference
int &ref2 = ival; // error: non-const reference to a const object
c) A const reference can be initialized as a right value or a different type.
int i = 42;
// legal for const references only
const int &r = 42;
const int &r2 = r+i;
double dval = 3.14;
const int &ri = dval;
// which is equal to the following
int temp = dval; // a force transform
const int &ri = temp; // bind ri to that temp
Part 3. ‘const’ used on pointers
a) If ‘const’ is on the left of *, data is const, we call it ‘const data pointer’, and if ‘const’ is on the right of *, pointer is const, we call it ‘const pointer’;
const int i = 9;
const int *p1 = &i; // data is const, pointer is not
int const *p2 = &i; // data is const, pointer is not
int* const p2 = &i; // data is not, pointer is const
b) A const data cannot be bind with a normal pointer, while a const data pointer can be bind with a normal data, but cannot modify the value through the pointer;
const double *cptr;
*cptr = 42; // error: a const data pointer
const double pi = 3.14;
double *ptr = π // error: const data cannot be binded with normal pointer
void *pv = π // error: const data cannot be binded with normal pointer
double dval = 3.14;
cptr = &dval; //ok: but cannot change dval though cptr
c) A const pointer points to a fixed object and cannot be re-pointed to other objects.
int errNumb = 0;
int* const curErr = &errNumb; // curErr is a const pointer
curErr = curErr; // error: const pointer cannot be redefined
typedef string *pstring;
const pstring cstr;
// wrong interpretation of the const pstring cstr
const string *cstr;
// correct interpretation
string* const cstr;
Part 4. ‘const’ used on parameter passing
a) const parameters by reference avoid parameters being modified in the function calls;
b) const return value by reference avoid the result being modified;
c) const member functions reject modification of any member variables, except those with ‘mutable’ declarations, and const functions can only call other const functions;
class Dog{
int age;
string name;
public:
Dog() {age = 3; name = "dummy";}
void setAge (const int& a) // const parameters by reference
{
age = a;
a++; // error: cannot be modified
}
const string& getName() {return name;} // const return value by reference
void printDogName() const // const functions
{
cout << name << "const" << endl; // prints "dummyconst"
age++; // error: in const functions cannot change any member variable
cout << getName() << endl; // error: non-const functions called in const functions
}
void printDogName() // non-const function overload
{
cout << getName() << "nonconst" << endl; // prints "dummynonconst"
}
}
int main() {
Dog d;
int i = 9;
d.setAge(i) // ok: age has been set to 9
const string& n = d.getName(); // n cannot be changed
d.printDogName(); // invoke non-const functions
const Dog d2;
d2.printDogName(); // invoke const version
}