Home

 › 

Articles

 › 

Understanding Encapsulation In C++, With Examples

C++ vs. JavaScript

Understanding Encapsulation In C++, With Examples

Encapsulation is a key concept in many programming languages. While it’s mostly used in OOP (object-oriented programming) languages, it’s a feature of many others too. When working with objects, we often want to “hide” the internal workings from outside classes. This helps to limit their modification and make them more robust and secure long-term. The way that encapsulation works in C++ differs from other languages like Python. In this article, we’re going to break down how encapsulation works in C++ and the ways to implement it.

What is Encapsulation in C++ and Why Use it?

Encapsulation generally refers to the wrapping of code into one unit, with limited access to the internal workings from outside classes. You can think of this as similar to confidential folders within an organization, which are protected. Only certain members of the organization will have access to all of the information, and there will often be hierarchical access depending on who needs to access which part of the details. Encapsulation works to achieve a very similar principle. This leads to a more user-friendly interface, data protection, and code that’s more secure.

How is Encapsulation in C++ Enforced?

C++ encapsulation works a bit differently from other languages. Whereas Python doesn’t have built-in access modifiers, C++ has access specifiers which are used to adjust the visibility of the code. These include public, private, and protected. As you may expect, public members can be accessed from anywhere within or outside the class. Private members, however, are only accessible from within the same class. Protected members can be accessed from within the class, but also from any derived classes.

We can also use friend functions in C++, which are functions that can access private and protected members outside the class. These can provide flexibility in using the code but do technically break encapsulation. Therefore, friend functions are usually avoided if possible, and used only whenever strictly necessary.

Examples of Encapsulation in C++

There are many situations where encapsulation is desirable. First, let’s consider the following example:

#include <iostream>
using namespace std;

class Circle {
private:
    double radius;

public: 
    void setRadius(double r) {
        if (r > 0)
            radius = r;
        else
            cout << "Invalid radius!" << endl;
    }

    double getRadius() {
        return radius;
    }

    double calculateArea() {
        return 3.14 * radius * radius;
    }
};

int main() {
    Circle myCircle;
    myCircle.setRadius(5.0);
    cout << "Radius: " << myCircle.getRadius() << endl;
    cout << "Area: " << myCircle.calculateArea() << endl;
    
    return 0;
}

Here, we’re defining the private “Circle” class, which has the “radius” private member variable. This can only be accessed from within the class. This class also has 3 public member functions – “setRadius”, “getRadius” and “calculateArea”.

If the input, “r”, is negative, then “setRadius” will report an error message. Therefore, we control access to this function to make sure the input isn’t invalid. As such, the “radius” variable is encapsulated, with its implementation hidden from external classes.

In this example, we’ve provided a radius of 5.0, which is retrieved by “getRadius” and used by “calculateArea” to calculate the area of the circle. The output can be seen in the image below.

Encapsulation in C++ is illustrated with an example.

Encapsulation in C++ with protected members

The previous example enforced encapsulation by using private members. However, this can also be done using protected members instead. For example, consider this code:

#include <iostream>
using namespace std;

class Circle {
protected:
    double radius;

public:
    void setRadius(double r) {
        if (r > 0)
            radius = r;
        else
            cout << "Invalid radius!" << endl;
    }

    double getRadius() {
        return radius;
    }

    double calculateArea() {
        return 3.14 * radius * radius;
    }
};

class Cylinder : public Circle {
private:
    double height;

public:
    void setHeight(double h) {
        if (h > 0)
            height = h;
        else
            cout << "Invalid height!" << endl;
    }

    double getHeight() {
        return height;
    }

    double calculateVolume() {
        return calculateArea() * height;
    }
};

int main() {
    Cylinder myCylinder;
    myCylinder.setRadius(3.0);
    myCylinder.setHeight(5.0);

    cout << "Radius: " << myCylinder.getRadius() << endl;
    cout << "Height: " << myCylinder.getHeight() << endl;
    cout << "Area: " << myCylinder.calculateArea() << endl;
    cout << "Volume: " << myCylinder.calculateVolume() << endl;

    return 0;
}

This code block uses a similar example but with some modifications. Firstly, we have the extr “Cylinder” class, which is derived from “Circle”. As such, “Cylinder” inherits the functions from “Circle”. Since this class is protected instead of private, we can use the functions from within the derived class. We create an instance of “Cylinder”, called “myCylinder”, set the radius and height, and then calculate the area and volume. This still provides some level of encapsulation but has a little more flexibility than private members.

An example of encapsulation using protected members.

Non-encapsulated example

To show the differences between encapsulated and non-encapsulated code, we can modify the first example to no longer be encapsulated. This can be described as such:

#include <iostream>
using namespace std;

double setRadius(double r) {
    if (r > 0)
        return r;
    else {
        cout << "Invalid radius!" << endl;
        return 0.0;
    }
}

double getRadius(double radius) {
    return radius;
}

double calculateArea(double radius) {
    return 3.14 * radius * radius;
}

int main() {
    double myRadius = setRadius(5.0);
    double myArea = calculateArea(myRadius);

    cout << "Radius: " << myRadius << endl;
    cout << "Area: " << myArea << endl;

    return 0;
}

We’ve removed the “Circle” class here and replaced the member functions with non-member functions. Therefore, instead of accessing the member variables, the functions take parameters as arguments. We still check the validity of the radius value. The “setRadius” function stores the radius value in “myRadius”, which is passed to “calculateArea” in order to return the area of the circle. Overall, this means that direct access to the values is possible from outside the class The result is the same, as can be seen in the image, but encapsulation in C++ does allow code to be better organized and more reusable.

The first example program was modified to work without encapsulation.

Wrapping Up

Encapsulation is a key concept to know about for all programmers, especially those using OOP languages. While you can achieve a similar function by using local variables, encapsulation is preferable. This is because it helps to make code more robust, immune to outside influence and accidental modification, and often leads to more simplified and organized code. C++ enforces encapsulation using access specifiers, but this can be mitigated by using friend functions where applicable.

Frequently Asked Questions

What is encapsulation in C++?

Encapsulation is the concept of hiding the internal data of a class from outside classes, to prevent accidental modification, and to make code robust and more user-friendly. This is done by controlling access to the class, and grouping functions and data into a single unit.

How do you enforce encapsulation in C++?

C++ enforces encapsulation by declaring class members as protected or private, using access specifiers. Public member functions are used to interact with these.

Why is encapsulation important?

Encapsulation is essential for hiding data and providing an abstract interface, where only the necessary details are exposed to outside classes. This helps code to be more organized, reusable, and intuitive.

What are protected and private members?

Protected members can be accessed from within a class and derived classes, but private members can only be accessed from within the same class.

What are access specifiers?

These are keywords which are used to define the visibility of class members. These can be public, private or protected.

How do inheritance and encapsulation work together?

Both are important concepts in making code reusable and controlling access. These are both used to enforce polymorphism, where derived class objects can be treated as if they’re objects from the base class. By encapsulating the base class and inheriting its members, derived classes can override their behavior without affecting the base class interface.

To top