Master Const Usage in C++: An In-Depth Exploration with Examples

Discover the power of ‘const’ in C++ through this comprehensive guide. This article will delve into various aspects of const usage in C++, so you can get excellent command over it.

This C++ const article includes:

  • const member variables,
  • const member functions,
  • const objects,
  • const parameters in functions,
  • Overloading const and non-const functions,
  • function overloading with const and non-const parameters

The “const” keyword enhances code robustness, readability, and maintainability by enforcing immutability and preventing unintended modifications.

Const Member Variable:

A const member variable is a data member within a class that cannot be modified after its initialization. It ensures that the value remains unchanged throughout the object’s lifetime. To declare a const member variable, use the “const” keyword before the data type.

Example:

class Circle {
public:
    const double pi = 3.14159;
    const double radius;    
    Circle(double r) : radius(r) {}
};

Const Member Function:

A const member function promises not to modify the object’s state. It is a member function declared with the “const” keyword after the function’s parameter list. Const member functions can be invoked on both const and non-const objects.

Example:

class Circle {
public:
    double calculateArea() const {
        return pi * radius * radius;
    }
    
private:
    const double pi = 3.14159;
    double radius;
};

Const Object:

A const object is an instance of a class that cannot be modified after its creation. It ensures that member variables and member functions marked as const can be accessed but not modified.

Example:

I am writing the complete code with explanation so you can understand better.

class Circle {
public:
    const double pi = 3.14159;
    const double radius;

    Circle(double r) : radius(r) {}

    double calculateArea() const {
        return pi * radius * radius;
    }
};

int main() {
    const Circle smallCircle(2.0);  // Creating a const object

    double area = smallCircle.calculateArea();
    std::cout << "Area of the circle: " << area << std::endl;

    // The following line would result in a compilation error since smallCircle is const
    // smallCircle.radius = 3.0;  // Error: Cannot modify a const member variable

    return 0;
}

In this example, we have a Circle class with a const member variable pi and a const member variable radius. The Circle constructor initializes the radius, and the calculateArea() method calculates the area of the circle.

In the main() function, we create a const object smallCircle with a radius of 2.0. We calculate and display the area using the calculateArea() method. Attempting to modify the radius of the smallCircle object would result in a compilation error, as indicated in the commented line.

This demonstrates how const objects ensure that member variables cannot be modified after creation, promoting the immutability of the object’s state.

Const Parameter in a Function:

A const parameter in a function indicates that the parameter value remains unaltered within the function. This prevents inadvertent changes and assures callers that their input won’t be modified.

Example:

void printValue(const int num) {
    // num = 10; // Error: Cannot modify a const parameter
    cout << "Value: " << num << endl;
}

Overloading const and non-const functions:

Function overloading permits multiple functions with the same name but different parameters. You can overload both const and non-const member functions, allowing for finer control based on the object’s constness.

Example:

class MyClass {
public:
    void showInfo() { cout << "Non-const function" << endl; }
    void showInfo() const { cout << "Const function" << endl; }
};

int main() {
    MyClass obj1;
    const MyClass obj2;

    obj1.showInfo(); // Calls the non-const version
    obj2.showInfo(); // Calls the const version
}

function overloading with const and non-const parameters:

If you have same data type in overloaded functions, and differ with const and non const, and those data are of reference or pointer type , only then you can overload the functions. Let’s see by examples:

1)const, non-const parameters only data type

This function overloading will NOT work. Because parameters of both print function only differ by non-cosnt and consnt.

class Printer {
public:
    void print(const int num) {
        cout << "Printing const number: " << num << endl;
    }

    void print(int num) {
        cout << "Printing non-const number: " << num << endl;
    }
};

2)const, non-const parameters reference type

This function overloading will work. Because parameters of both print function are of “reference type”

class Printer {
public:
    void print(const int& num) {
        cout << "Printing const number: " << num << endl;
    }

    void print(int& num) {
        cout << "Printing non-const number: " << num << endl;
    }
};

int main()
{
    Printer printer;
    int x = 5;
    const int y = 10;

    printer.print(x);     // Calls the non-const version
    printer.print(y);       // Calls the const version
    

    return 0;
}

3)const, non-const parameters pointer type

This function overloading will work. Because parameters of both print function are of “pointers type”

class Printer {
public:
    void print(const int* num) {
        cout << "Printing const number: " << *num << endl;
    }

    void print(int* num) {
        cout << "Printing non-const number: " << *num << endl;
    }
};

int main()
{
    Printer printer;
    int x = 5;
    const int y = 10;

    printer.print(&x);     // Calls the non-const version
    printer.print(&y);       // Calls the const version
    

    return 0;
}

Conclusion:

By comprehending the intricacies of const usage in various contexts, developers can write more robust and reliable C++ code. Const member variables, const member functions, const objects, const parameters, and function overloading involving const and non-const parameters all contribute to code maintainability and readability. Incorporating const correctness ensures that modifications are controlled, ultimately leading to safer and more predictable software development.