DEV Community

Cover image for Object-Oriented Programming in C++: Access Modifiers
Meet Gor
Meet Gor

Posted on • Originally published at mr-destructive.github.io

Object-Oriented Programming in C++: Access Modifiers

Introduction

Moving on to Part 2 of Object-Oriented Programming in C++, we will look into the concept of access modifiers which we skipped in the first section. This won't be a comprehensive guide on access modifiers as it requires some other concepts like Inheritance which we will introduce in the next few sections. This series will be like connecting the pieces of OOP together and building a good foundation.

In this part, we will discuss the access modifiers and their related concepts. The below is a gist of what will be cob\verd in this part.

  • Understanding Access Modifiers
  • Type of Access Modifiers
    1. Private
      • Getters
      • Setters
    2. Public
    3. Protected
      • Introduction to Derived and Friend classes

Without wasting any time, let's roll in.

What are Access Modifiers

Access Modifiers as the name suggests they are used to change the accessibility of properties and methods in a Class. That means if we want a certain scope of our code to access the class members we can specify that using access modifiers. Access Modifiers form the basics or the pillar for Data Encapsulation in OOP.

Data Encapsulation

Data Encapsulation is terminology in OOP to keep all the components in a single entity or unit. Here the components are properties and methods and they are contained in a single unit called Class. We need to carefully use the class members i.e. properties and methods in order to avoid security and limiting certain members to be available for a specific scope or block of code.

Hence, the Encapsulation of class members helps in structuring the class in a secure and allows access in a particular expected way.

Types of Access Modifiers in C++

We do have certain modifiers or limiters for accessing class members in C++. We can either keep the class members limited to the class itself (and friend class), keep them open to the global scope, or restrict them to certain classes only(derived and friend classes).

Let's discuss them one by one.

Private

This access modifier allows us to access the class members only to the class methods and the friend functions and classes. We will discuss what friend classes are in the next few parts of the series. This restricts the usage of the class members directly from the main function or other scopes in our program. You can use private: to indicate the below declared properties and methods are private to the class.

class Name
{ 
    private:
        int name;
        //other properties and methods
}
Enter fullscreen mode Exit fullscreen mode

OR (don't specify anything it is private by default)

class Name
{ 
    int name;
    //other properties and methods
}
Enter fullscreen mode Exit fullscreen mode

This is assigned to every member of the class by default. So that is why we explicitly told to make it public in an example in the previous part of the series. Let's see what happens if we do not make it public.

#include<iostream>
using namespace std;

class Animal{
    int legs;
    string name;
    void print()
    {
        cout<<name<<" has "<<legs<<" legs.\n";
    }
};

int main()
{

    Animal dog;
    dog.name="Floyd";
    dog.legs=4;
    dog.print();

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

image.png

You can see we cannot directly use those properties and methods which are set as private. It is a convention to keep properties private and create public methods to access those from the rest of the program. The public methods used to access and modify the value of the private properties are called getters and setters respectively.

Getters

Getters are the public methods of a class that are used to access a value to the private properties of that class. It is a function that returns the data of that particular property. We access the function as normally as we access the public functions.

We define the getter function as:

datatype getpropertyname()
{
    return propertyname;
}
Enter fullscreen mode Exit fullscreen mode

We can access the getter function as a normal public function, but this function returns a value, so we can store it in a variable and do all sorts of things.

classname objname;
court<<objname.getpropertyname()<<endl;
Enter fullscreen mode Exit fullscreen mode

Setters

Setters are the public methods of a class that are used to assign/modify the value of the private properties of that class. It is a function that simply assigns the private properties to data of the data which is passed in as an argument to the function. We access the function as normally as we access the public functions. We have to pass in the value to assign the property to the function.

We define the setter function as:

datatype setpropertyname(datatype x)
{
    propertyname = x;
}
Enter fullscreen mode Exit fullscreen mode

We can access the setter function as a normal public function, but this function takes in a parameter, so need to pass in the value to assign it the same as the correspondent data type of that property.

classname objname;
objname.setpropertyname(data);
Enter fullscreen mode Exit fullscreen mode

So, after applying the getter and setter concept to our example, we can use them and make the properties private without any issues.

#include<iostream>
using namespace std;

class Animal{
    int legs;
    string name;
    public:

    // take in a parameter of type same as of the property 
    void setName(string dogname)   
    {
        name=dogname; 
        // assign the property a value same as of the parameter       
    }

    // return type should be same as of the property 
    string getName()   
    {
        return name;
    }

    void setleg(int noflegs)
    {
        legs=noflegs;
    }

    int getleg()
    {
        return legs;
    }
};

int main()
{
    Animal dog;
    dog.setName("Flyod");
    dog.setleg(4);
    cout<<dog.getName()<<endl;
    cout<<dog.getleg()<<endl;

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

image.png

image.png

The above code runs successfully, and hence we make our program more secure and provide limited access to the rest of the components. You can see how we have passed the data as the parameter to the setter function, it should be the appropriate data-type with the property you are trying to set and also the same return type for the getter function.

The code is also much readable and structured for others to read and understand. It might seem a silly thing but it really improves the maintainability in the longer run.

Public

This might be familiar till now, we have been using this access modifier till now and it is quite straightforward to understand. We have created the getter and setter function using this access modifier.

So, the public access modifier makes the class members be accessible anywhere in the program. This might be OK for many small applications but it is not ideal to use them for production-level applications as it might cause undesired consequences i.e. BUGS.

We need to explicitly write public in the class definition, as private is set by default. So, as a simple example, as we saw in the previous part, it can be a lot easier to go with the public to understand OOP but the main OOP really shines in aspects like Encapsulation and Inheritance of Classes, which we will surely see in the upcoming parts.

This is the example from the previous part:

#include<iostream>
using namespace std;

class Animal
{
    public:
        int legs;
        string name;
        void print()
        {
            cout<<name<<" has "<<legs<<" legs.\n";
        }
};

int main()
{
    Animal dog;            // create an object of class Animal

    dog.name="Floyd";     // assign the class property to actual data in memory
    dog.legs=4;                 
    dog.print();          // call a method(function) associated to object's class

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

public-class

image.png

As explained earlier, it is accessible to the main function or other scopes as well. We can access them using the dot separator(.) to assign it or to call the method.

Protected

This is quite a handy access modifier, as it allows us to have the flexibility to keep the class members private and accessible to its derived or friend class. We will see the derived and friend classes in the next few parts. But for now, let's understand in an abstracted way.

Derived Class(Child Class/ Sub Class)

This is a concept in Inheritance, i.e. to pass the members of a class to another. So, there has to be two classes, the main(parent class) and another class that will inherit or take in the members from the parent class. So, the derived class has access to its public and protected members only.

Friend class

A friend class is a class that is allowed to access its private and protected properties or methods. It is kind of a special tag assigned to a class that it can access certain class' members. We will see it in detail afterward, right now, it's enough to understand, friend class is a class that can access a particular class' members may it be private or protected.

The difference between a friend and a derived class is that a friend class can access the private members of the class to which it is a friend, but a derived class can't. Friend class also can't be inherited. Again, we will see this is in detail.

So, it doesn't make sense for me to explain protected here. But just assume friend classes and derived classes are a thing.

#include<iostream>
using namespace std;

class Animal
{
    public:
        int legs;
        string type;

        void print()
        {
            cout<<type<<" has "<<legs<<" legs.\n";
        }

    protected:
        string name;
};


int main()
{

    Animal dog;
    dog.type="dog";
    dog.legs=4;
    dog.name="Floyd";
    dog.print();

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

image.png

This gives an error as protected members can be accessed only by derived or friend classes since we are accessing it from the main function, it's not allowed in the global scope. We can only access the protected members from the derived or friend classes.

So, let's derive a class from the base class(Animal), and after that, we can see protected members in action.

#include<iostream>
using namespace std;

class Animal
{
    public:
        int legs;
        string type;

        void print()
        {
            cout<<type<<" has "<<legs<<" legs.\n";
        }

    protected:
        string name;
};

class Pet:public Animal 
{
    public:
        void print()
        {
            name="Floyd";
            cout<<name<<" is a "<<type<<endl;
            cout<<type<<" has "<<legs<<" legs.\n";
        }

};

int main()
{

    Pet dog;
    dog.type="dog";
    dog.legs=4;
    dog.print();

    return 0;
}


Enter fullscreen mode Exit fullscreen mode

image.png

image.png

We have accessed the protected property name in the derived class Pet. Yes, this is how we derive a class in C++,

// A child class serived from base class
class NewClassName: public BaseClassName
{
     // properties and methods
};
Enter fullscreen mode Exit fullscreen mode

So, after deriving the Pet class from Animal class, we have access to its public and protected class as well. We simply assigned one of the protected members from its base class i.e. name and used it in the function print.

This is how you can use protected members in a derived class, also you can do it in friend class, but we will look at that in a separate part. Remember you can use getters and setters as well to assign and access those protected members. Keeping it simple and easy to understand is what a protected access modifier can provide.

Protected access modifiers are quite great and provide much more flexibility than private and more privacy than public access modifiers.

Which to use when?

It is often a good practice to use private members, but it might be not possible to make everything private, so we can use certain properties as private, some methods as public and protected as well as per requirement and complexity.

acmod.png

Looking at the above chart, you can analyze your problem and work a way around to find the perfect secure match for your application.

Rember to use public members only when you have to explicitly use through the program. If you find that, this member shouldn't be introduced in certain scope then use make it private or protected.

If there is some kind of hierarchy in the program and its components, analyze and make a structure of it to have a better understanding of the program flow.

Conclusion

So, from this part, we were able to understand the access modifiers and got somewhat of a dive into Inheritance. There were some concepts like Friend and Derived classes, Inheritance, Encapsulation which were just explained in short, but they are a topic that deserves separate attention. We'll discuss them in the upcoming parts.

Thanks for reading. Hope you understood the concepts in a better way. Until then, as always, Happy Coding :)

Discussion (0)