Object-Oriented Programming in C++

Vibhanshu SinghVibhanshu Singh
10 min read

Before we go further, we need to understand what OOP is. Basically, OOP, or Object-Oriented Programming, is one of several programming approaches. It's a set of rules, ideas, or concepts designed to help us solve real-world problems. The main idea behind OOP is that it lets us represent real-life objects and entities within our computer systems, which we do using classes and objects.

Classes and Objects

Classes are the building blocks of OOP and are user-defined data types (a more complex kind of data type).
For example, suppose we have a class for a user, with characteristics like name, gender, height, weight, etc. Let’s say there’s a person named Ram with the following characteristics: name: Ram, gender: Male, height: 175 cm, weight: 70 kg, and so on. In this case, Ram is an object (or instance) of that class.

Creating a class in C++

#include <iostream>

class Person {

};
int main() {

}

Here’s what a typical class declaration looks like. We use the keyword class, followed by the name of the class (Person), then parentheses, and end with a semicolon (;).
Since the class above is empty, we need to add members, which will include its attributes and behaviors.

#include <iostream>
using std::string;

class Person {
    string Name;
    string Gender;
    int Age;
};
int main() {

}

Now, let's learn how to create an object of the class above:

#include <iostream>
using std::string;

class Person {
    string Name;
    string Gender;
    int Age;
};
int main() {
    Person Vibhanshu;
}

By doing this, we have successfully created an object of the class above. In the example, Person is the class, and Vibhanshu is an object of that class.

Access Modifiers

By default, all members of the class (like Name, Gender, and Age) are private. To manage this, we use access modifiers. These are of three types: public, private, and protected.

  • public: Anything in the class will be accessible from anywhere in the program.

  • private: Everything in the class will be private and won’t be accessible throughout the program.

  • protected: falls between public and private

#include <iostream>
using std::string;

class Person {
    string Name;
    string Gender;
    int Age;
};
int main() {
    Person Vibhanshu;
}
#include <iostream>
using std::string;

class Person {
private:
    string Name;
    string Gender;
    int Age;
};
int main() {
    Person Vibhanshu;
}

The two code snippets above are the same because, by default, all class members are private. To address the previous issue, we need to make the following changes:

#include <iostream>
using std::string;

class Person {
public:
    string Name;
    string Gender;
    int Age;
};
int main() {
    Person Vibhanshu;
}

Now, let’s dive deeper into the details of the program.

#include <iostream>
using std::string;

class Person {
public:
    string Name;
    string Gender;
    int Age;

    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
};

int main() {
    Person Vibhanshu;
    Vibhanshu.Name = "Vibhanshu";
    Vibhanshu.Gender = "Male";
    Vibhanshu.Age = 21;
    Vibhanshu.IntroduceYourself();
}

Now, let’s say we need to create another object in our program. How do we do that?

#include <iostream>
using std::string;

class Person {
public:
    string Name;
    string Gender;
    int Age;

    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
};

int main() {
    Person Vibhanshu;
    Vibhanshu.Name = "Vibhanshu";
    Vibhanshu.Gender = "Male";
    Vibhanshu.Age = 21;
    Vibhanshu.IntroduceYourself();

    Person Harshit;
    Harshit.Name = "Harshit";
    Harshit.Gender = "Male";
    Harshit.Age = 19;
    Harshit.IntroduceYourself();
}

But what if we have, say, 100 people? The above approach isn’t an efficient way to handle that. To solve this, we use the concept of constructors.

Constructors

Constructors are special methods/functions that are called each time an object of a class is created.

#include <iostream>
using std::string;

class Person {
public:
    string Name;
    string Gender;
    int Age;

    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
};

int main() {
    Person Vibhanshu;
    Vibhanshu.IntroduceYourself();

    Person Harshit;
    Harshit.IntroduceYourself();
}

When you run the above code, you'll get output with random values. This happens because of the default constructor, which is automatically created when the object of the class is instantiated.

There are three rules for creating a constructor in C++:

  1. A constructor does not have a return type.

  2. A constructor has the same name as the class it belongs to.

  3. A constructor must be public.

#include <iostream>
using std::string;

class Person {
public:
    string Name;
    string Gender;
    int Age;

    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
};

int main() {
    Person Vibhanshu = Person("Vibhanshu", "Male", 21); //invoking the constructor
    Vibhanshu.IntroduceYourself();

    Person Harshit = Person("Harshit", "Male", 19);
    Harshit.IntroduceYourself();
}

Four Pillars of Object-Oriented Programming

  1. Encapsulation

  2. Abstraction

  3. Inheritance

  4. Polymorphism

Encapsulation: Encapsulation is the process of bundling or grouping together data and the methods that operate on that data within a class, with the goal of preventing outside access to the data. It ensures that the data can only be interacted with or modified through the class's methods.
For example:

#include <iostream>
using std::string;

class Person {
private:
    string Name;
    string Gender;
    int Age;
public:
    void setName(string name) {
        Name = name;
    }
    string getName() {
        return Name;
    }
    void setGender(string gender) {
        Gender = gender;
    }
    string getGender() {
        return Gender;
    }
    void setAge(int age) {
        Age = age;
    }
    int getAge() {
        return Age;
    }
    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
};

int main() {
    Person Vibhanshu = Person ("Vibhanshu", "Male", 21);
    Vibhanshu.setName("Nanmum");
    Vibhanshu.setAge(14);
    std::cout << Vibhanshu.getName() << " is " << Vibhanshu.getAge() << " years old." << std::endl;
}

Abstraction: Abstraction is the process of hiding complex details behind a simple interface, making those things appear straightforward.
For example:

#include <iostream>
using std::string;

class CheckPerson {
    virtual void EligibleforVote() = 0; //By using the virtual keyword and assigning it the value 0, this function now becomes mandatory. This means that anyone who opts in (or 'checks the box') for the vote will have to pass this test.
};

class Person:CheckPerson {
private:
    string Name;
    string Gender;
    int Age;
public:
    void setName(string name) {
        Name = name;
    }
    string getName() {
        return Name;
    }
    void setGender(string gender) {
        Gender = gender;
    }
    string getGender() {
        return Gender;
    }
    void setAge(int age) {
        Age = age;
    }
    int getAge() {
        return Age;
    }
    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
    void EligibleforVote() {
        if (Age >= 18)
            std::cout << Name << " is eligible for vote." << std::endl;
        else
            std::cout << Name << " is not eligible for vote." << std::endl;
    }
};

int main() {
    Person Vibhanshu = Person ("Vibhanshu", "Male", 21);
    Person Mayank = Person ("Mayank", "Male", 14);
    Vibhanshu.EligibleforVote();
    Mayank.EligibleforVote();
}

In the example above, the complexity of determining voting eligibility is hidden from the user, demonstrating abstraction.

Inheritance: It means inheriting the properties of one class into another class, with modifications in the new class.
For example:

#include <iostream>
using std::string;

class CheckPerson {
    virtual void EligibleforVote() = 0; //By using the virtual keyword and assigning it the value 0, this function now becomes mandatory. This means that anyone who opts in (or 'checks the box') for the vote will have to pass this test.
};

class Person:CheckPerson {
private:
    string Name;
    string Gender;
    int Age;
public:
    void setName(string name) {
        Name = name;
    }
    string getName() {
        return Name;
    }
    void setGender(string gender) {
        Gender = gender;
    }
    string getGender() {
        return Gender;
    }
    void setAge(int age) {
        Age = age;
    }
    int getAge() {
        return Age;
    }
    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
    void EligibleforVote() {
        if (Age >= 18)
            std::cout << Name << " is eligible for vote." << std::endl;
        else
            std::cout << Name << " is not eligible for vote." << std::endl;
    }
};

class Developer: Person {
public:
    string FavProgLang;
    Developer (string name, string gender, int age, string favproglang)
        :Person(name, gender, age)
    {
        FavProgLang = favproglang;
    }
    void FixBug() {
        std::cout << getName() << " is fixing bug using " << FavProgLang << std::endl;
    }
};

int main() {
    Developer Vibhanshu = Developer ("Vibhanshu", "Male", 21, "Python");
    Developer Mayank = Developer ("Mayank", "Male", 14, "Java");
    Vibhanshu.FixBug();
    Mayank.FixBug();
}
#include <iostream>
using std::string;

class CheckPerson {
    virtual void EligibleforVote() = 0; //By using the virtual keyword and assigning it the value 0, this function now becomes mandatory. This means that anyone who opts in (or 'checks the box') for the vote will have to pass this test.
};

class Person:CheckPerson {
protected:
    string Name;
private:
    string Gender;
    int Age;
public:
    void setName(string name) {
        Name = name;
    }
    string getName() {
        return Name;
    }
    void setGender(string gender) {
        Gender = gender;
    }
    string getGender() {
        return Gender;
    }
    void setAge(int age) {
        Age = age;
    }
    int getAge() {
        return Age;
    }
    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
    void EligibleforVote() {
        if (Age >= 18)
            std::cout << Name << " is eligible for vote." << std::endl;
        else
            std::cout << Name << " is not eligible for vote." << std::endl;
    }
};

class Developer: Person {
public:
    string FavProgLang;
    Developer (string name, string gender, int age, string favproglang)
        :Person(name, gender, age)
    {
        FavProgLang = favproglang;
    }
    void FixBug() {
        std::cout << Name <<" is fixing bug using " << FavProgLang << std::endl;
    }
};

int main() {
    Developer Vibhanshu = Developer ("Vibhanshu", "Male", 21, "Python");
    Developer Mayank = Developer ("Mayank", "Male", 14, "Java");
    Vibhanshu.FixBug();
    Mayank.FixBug();
}

Polymorphism: The word 'polymorphism' comes from Greek. 'Poly' means many, and 'morph' means form, so it essentially means 'many forms.'
For example:

#include <iostream>
using std::string;

class CheckPerson {
    virtual void EligibleforVote() = 0; //By using the virtual keyword and assigning it the value 0, this function now becomes mandatory. This means that anyone who opts in (or 'checks the box') for the vote will have to pass this test.
};

class Person:CheckPerson {
protected:
    string Name;
private:
    string Gender;
    int Age;
public:
    void setName(string name) {
        Name = name;
    }
    string getName() {
        return Name;
    }
    void setGender(string gender) {
        Gender = gender;
    }
    string getGender() {
        return Gender;
    }
    void setAge(int age) {
        Age = age;
    }
    int getAge() {
        return Age;
    }
    void IntroduceYourself() {
        std::cout << "Name - " << Name << std::endl;
        std::cout << "Gender - " << Gender << std::endl;
        std::cout << "Age - " << Age << std::endl;
    }
    Person(string name, string gender, int age) { //constructor
        Name = name;
        Gender = gender;
        Age = age;
    }
    void EligibleforVote() {
        if (Age >= 18)
            std::cout << Name << " is eligible for vote." << std::endl;
        else
            std::cout << Name << " is not eligible for vote." << std::endl;
    }
    void Work() {
    std::cout << Name << " is performing monitoring tasks." << std::endl;
    }
};

class Developer: public Person {
public:
    string FavProgLang;
    Developer (string name, string gender, int age, string favproglang)
        :Person(name, gender, age)
    {
        FavProgLang = favproglang;
    }
    void FixBug() {
        std::cout << Name << " is fixing bug using " << FavProgLang << std::endl;
    }
    void Work() {
    std::cout << Name << " is writing code." << std::endl;
    }
};

class Teacher: public Person {
public:
    string Subject;
    void PrepareLesson() {
        std::cout << Name << " is preparing " << Subject << " lesson " << std::endl;
        }
        Teacher(string name, string gender, int age, string subject)
            :Person(name, gender, age)
        {
            Subject = subject;
        }
        void Work() {
        std::cout << Name << " is attending calls." << std::endl;
        }
}; 

int main() {
    Developer Vibhanshu = Developer ("Vibhanshu", "Male", 21, "Python");
    Teacher Mayank = Teacher ("Mayank", "Male", 14, "English");
    Vibhanshu.Work();
    Mayank.Work();
    Vibhanshu.EligibleforVote();
    Mayank.EligibleforVote();
}

In the above example, the function void has many forms, which is essentially what polymorphism is.

Note: This is NOT a professional blog.

1
Subscribe to my newsletter

Read articles from Vibhanshu Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vibhanshu Singh
Vibhanshu Singh