What are Object-Oriented Programming Concepts?

What are Object-Oriented Programming Concepts?

21 Oct 2024
Beginner
33.5K Views
59 min read
Learn with an interactive course and practical hands-on labs

Java Programming Course

Object-Oriented Programming Concepts

Object-Oriented Programming (OOP)is important for developers looking to create flexible and efficient applications. Imagine organizing code into reusable objects, allowing you to create, manage, and modify applications with ease. OOPs enables encapsulation, inheritance, polymorphism, and abstraction, making it easier to model real-world problems and create scalable, maintainable solutions without added complexity.

In this OOPs tutorial, I’ll explain the key concepts of object-oriented programming, how they simplify software development by enabling modular design, and why mastering them is key to creating robust, efficient applications.

What is object-oriented programming?

  • Object-Oriented Programming (OOP) is a way for you to organize your code by thinking of it like real-life objects.
  • It helps you group things together, so your code is easier to work with and reuse.
  • With OOPs, you can use encapsulation to keep some parts of your code hidden and only show what’s necessary.
  • Inheritance lets you take parts of old code and reuse it for new things.
  • Polymorphism helps your code change depending on the situation, and abstraction makes things simple by showing just what’s needed and hiding extra details.
  • Using OOPs concepts makes it easier for you to build and manage big projects because it breaks problems into smaller, simpler pieces.

Before exploring OOPs, it is important for you to understand the basics of method declaration. Knowing these prerequisites will help you grasp how to create and use methods effectively in your programming. This knowledge forms a strong foundation that supports your understanding of OOP concepts.

Pre-requisites

Let’s look at what you need to know about method declaration in a simpler way. A method declaration has six main parts:

1. Access Modifier

This tells you who can use the method in your program. There are four types:

  • Public: Anyone can use it.
  • Protected: Only classes in the same package and subclasses can use it.
  • Private: Only the class that has the method can use it.
  • Default: If you don’t use any modifier, it can be used within the same class and package.

2. Return Type

  • This is the type of value the method will give back.
  • If the method doesn’t return anything, you use void.

3. Method Name

  • This is how you name the method.
  • There are some rules for naming, but it’s a bit different from naming fields.

4. Parameter List

  • This is where you list the inputs the method needs.
  • You write the type of each input followed by its name, separated by commas.
  • If there are no inputs, you just use empty parentheses ( ).

5. Exception List

  • This is where you mention any errors the method might cause.

6. Method Body

  • This is the block of code that does the work of the method.
  • It’s enclosed in curly braces { }.

Let’s explore the fundamental concepts of Object-Oriented Programming (OOP) and discover how they can enhance your coding skills and make application development easier.

OOPs Concepts

Following are the OOPs Concepts:

OOPs Concepts

  1. Class
  2. Objects
  3. Data Abstraction
  4. Encapsulation
  5. Inheritance
  6. Polymorphism
  7. Dynamic Binding
  8. Message Passing

1. Class

  • A class is like a blueprint for creating objects.
  • It defines the properties (what things have) and methods (what things can do) that the objects created from it will have.
  • Using classes helps you organize your code and keep it neat.
  • In a class, you can specify unique features that each object will have while also sharing common behavior.
  • This makes it easier to create similar objects without repeating code.
  • When designing a class, it’s essential to think about what features and actions will be needed for the objects that will use it.
  • A well-designed class helps you manage your code better and makes it easier to understand. 
  • Overall, classes are a fundamental part of organizing and building software efficiently.
Class

Explanation

  • This diagram shows a class named Car, which acts as a blueprint for creating car objects.
  • It has three attributes: color, model, and year, which describe the car's features.
  • The class also includes three methods: start(), stop(), and honk(), which define what actions a car can perform.

2. Objects

  • An object is like a specific example made from a class blueprint.
  • It has its own properties (like color and size) and can perform actions (like run or jump) defined in the class.
  • Using objects helps you use the features of a class while giving each one unique values.
  • When you create an object, it gets the shared behavior from the class but can also have its own specific details.
  • This makes it simple to manage similar items without rewriting code.
  • Thinking about what properties and actions your object needs is important when creating it.
  • A well-made object helps keep your code organized and clear, making it easier to work with.
  • Overall, objects are key to building and organizing software effectively.

Objects

Example


#include <iostream>
#include <string>
using namespace std;

class Car {
    string color;
    string model;
    int year;

public:
    // Constructor
    Car(string c, string m, int y) : color(c), model(m), year(y) {}

    // Methods
    void start() {
        cout << model << " is starting." << endl;
    }

    void stop() {
        cout << model << " is stopping." << endl;
    }

    void honk() {
        cout << model << " is honking." << endl;
    }
};

int main() {
    Car car1("Red", "Honda City", 2020);
    Car car2("Blue", "Hyundai Creta", 2021);

    car1.start();
    car2.honk();

    return 0;
}
            

class Car {
    String color;
    String model;
    int year;

    // Constructor
    Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    // Methods
    void start() {
        System.out.println(model + " is starting.");
    }

    void stop() {
        System.out.println(model + " is stopping.");
    }

    void honk() {
        System.out.println(model + " is honking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car1 = new Car("Red", "Honda City", 2020);
        Car car2 = new Car("Blue", "Hyundai Creta", 2021);

        car1.start();
        car2.honk();
    }
}
            

using System;

class Car {
    public string Color { get; }
    public string Model { get; }
    public int Year { get; }

    // Constructor
    public Car(string color, string model, int year) {
        Color = color;
        Model = model;
        Year = year;
    }

    // Methods
    public void Start() {
        Console.WriteLine($"{Model} is starting.");
    }

    public void Stop() {
        Console.WriteLine($"{Model} is stopping.");
    }

    public void Honk() {
        Console.WriteLine($"{Model} is honking.");
    }

    static void Main(string[] args) {
        Car car1 = new Car("Red", "Honda City", 2020);
        Car car2 = new Car("Blue", "Hyundai Creta", 2021);

        car1.Start();
        car2.Honk();
    }
}
            

class Car:
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year

    def start(self):
        print(f"{self.model} is starting.")

    def stop(self):
        print(f"{self.model} is stopping.")

    def honk(self):
        print(f"{self.model} is honking.")

# Creating objects of Car
car1 = Car("Red", "Honda City", 2020)
car2 = Car("Blue", "Hyundai Creta", 2021)

# Using methods on objects
car1.start()
car2.honk()
            

class Car {
    constructor(color, model, year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    start() {
        console.log(`${this.model} is starting.`);
    }

    stop() {
        console.log(`${this.model} is stopping.`);
    }

    honk() {
        console.log(`${this.model} is honking.`);
    }
}

// Creating objects of Car
const car1 = new Car("Red", "Honda City", 2020);
const car2 = new Car("Blue", "Hyundai Creta", 2021);

// Using methods on objects
car1.start();
car2.honk();
            

Output


Honda City is starting.
Hyundai Creta is honking.
    

Explanation

  • The Car class has three private attributes: color, model, and year.
  • A constructor initializes these attributes when a new Car object is created.
  • The class includes three methods: start, stop, and honk, which print messages to indicate the car's actions.
  • In the main function, two Car objects are created: car1 and car2, with different colors and models.
  • The program calls the start method on car1 and the honk method on car2, producing the corresponding output.

3. Data Abstraction

  • Data abstraction is like simplifying something by hiding the complicated parts and showing only what’s important.
  • It helps you concentrate on what an object does rather than how it does it.
  • By using data abstraction, you create an easy way to use your objects without needing to know all the details.
  • This keeps your code tidy and minimizes mistakes.
  • When building a system, consider which details can be kept hidden and what users need to know.
  • Good data abstraction helps you handle complexity and makes your code simpler to understand and manage.
  • Overall, data abstraction is key to creating organized and effective software.

Example


#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() = 0; // Pure virtual function

    void color() {
        cout << "The shape is colored." << endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {
        cout << "Drawing a Circle." << endl;
    }
};

class Square : public Shape {
public:
    void draw() override {
        cout << "Drawing a Square." << endl;
    }
};

int main() {
    Shape* circle = new Circle();
    Shape* square = new Square();

    circle->draw();
    circle->color();

    square->draw();
    square->color();

    delete circle;
    delete square;

    return 0;
}
            

using System;

abstract class Shape
{
    public abstract void Draw();

    public void Color()
    {
        Console.WriteLine("The shape is colored.");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a Circle.");
    }
}

class Square : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a Square.");
    }
}

class Program
{
    static void Main()
    {
        Shape circle = new Circle();
        Shape square = new Square();

        circle.Draw();
        circle.Color();

        square.Draw();
        square.Color();
    }
}
            

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def draw(self):
        pass

    def color(self):
        print("The shape is colored.")

class Circle(Shape):
    def draw(self):
        print("Drawing a Circle.")

class Square(Shape):
    def draw(self):
        print("Drawing a Square.")

circle = Circle()
square = Square()

circle.draw()
circle.color()

square.draw()
square.color()
            

abstract class Shape {
    abstract void draw();

    void color() {
        System.out.println("The shape is colored.");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a Circle.");
    }
}

class Square extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a Square.");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle();
        Shape square = new Square();

        circle.draw();
        circle.color();

        square.draw();
        square.color();
    }
}
            

class Shape {
    draw() {
        throw "Method not implemented.";
    }

    color() {
        console.log("The shape is colored.");
    }
}

class Circle extends Shape {
    draw() {
        console.log("Drawing a Circle.");
    }
}

class Square extends Shape {
    draw() {
        console.log("Drawing a Square.");
    }
}

const circle = new Circle();
const square = new Square();

circle.draw();
circle.color();

square.draw();
square.color();
            

Explanation

  • The Shape class is an abstract class with a pure virtual function draw and a concrete method color.
  • The draw the method must be implemented by any derived class while color provides a default implementation.
  • The Circle and Square classes inherit from Shape and provide their own implementations of the draw method.
  • In the main function, pointers to the base class Shape are used to create objects of Circle and Square.
  • The program calls the draw method on both shapes, followed by the color method on the circle object, producing the corresponding output.
  • Finally, the dynamically allocated memory for the shapes is released using.delete.

4. Encapsulation

  • Encapsulation is like putting the details of how something works inside a box and only showing what’s necessary on the outside.
  • It keeps the data safe and prevents outside parts from changing it directly.
  • With encapsulation, you create rules for how the data can be accessed or modified.
  • This means you can protect the object’s internal state and ensure it behaves correctly.
  • When designing your classes, think about which data should be hidden and how users will interact with it.
  • Good encapsulation helps you maintain control over your objects and makes your code more reliable and easier to understand.
  • Overall, encapsulation is essential for building strong and organized software.
Encapsulation

Example


#include <iostream>
using namespace std;

class BankAccount {
private:
    double balance;

public:
    BankAccount(double initialBalance) {
        balance = initialBalance;
    }

    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposited: " << amount << endl;
        } else {
            cout << "Deposit amount must be positive." << endl;
        }
    }

    double getBalance() {
        return balance;
    }
};

int main() {
    BankAccount myAccount(1000.0);
    myAccount.deposit(500.0);
    cout << "Current balance: " << myAccount.getBalance() << endl;

    return 0;
}
            

using System;

class BankAccount
{
    private double balance;

    public BankAccount(double initialBalance)
    {
        balance = initialBalance;
    }

    public void Deposit(double amount)
    {
        if (amount > 0)
        {
            balance += amount;
            Console.WriteLine("Deposited: " + amount);
        }
        else
        {
            Console.WriteLine("Deposit amount must be positive.");
        }
    }

    public double GetBalance()
    {
        return balance;
    }
}

class Program
{
    static void Main()
    {
        BankAccount myAccount = new BankAccount(1000.0);
        myAccount.Deposit(500.0);
        Console.WriteLine("Current balance: " + myAccount.GetBalance());
    }
}
            

class BankAccount:
    def __init__(self, initial_balance):
        self.balance = initial_balance

    def deposit(self, amount):
        if amount > 0:
            self.balance += amount
            print(f"Deposited: {amount}")
        else:
            print("Deposit amount must be positive.")

    def get_balance(self):
        return self.balance

my_account = BankAccount(1000.0)
my_account.deposit(500.0)
print("Current balance:", my_account.get_balance())
            

class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        balance = initialBalance;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: " + amount);
        } else {
            System.out.println("Deposit amount must be positive.");
        }
    }

    public double getBalance() {
        return balance;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount(1000.0);
        myAccount.deposit(500.0);
        System.out.println("Current balance: " + myAccount.getBalance());
    }
}
            

class BankAccount {
    constructor(initialBalance) {
        this.balance = initialBalance;
    }

    deposit(amount) {
        if (amount > 0) {
            this.balance += amount;
            console.log("Deposited: " + amount);
        } else {
            console.log("Deposit amount must be positive.");
        }
    }

    getBalance() {
        return this.balance;
    }
}

const myAccount = new BankAccount(1000.0);
myAccount.deposit(500.0);
console.log("Current balance: " + myAccount.getBalance());
            

Output


Deposited: 500
Current balance: 1500
    

Explanation

  • In this code, we define a BankAccount class with a private balance variable. We initialize the balance through the constructor and can deposit money using the deposit() method, which ensures the amount is positive before updating the balance. We can retrieve the current balance with the getBalance() method. In the main function, we create a BankAccount, deposit money, and print the updated balance.

Inheritance

  • Inheritance is like creating a new object by building on top of an existing one and reusing its properties and methods instead of starting from scratch.
  • It allows you to create a hierarchy where new classes inherit the behaviors and features of existing classes.
  • With inheritance, you can extend or customize the functionality of a base class while keeping its core elements.
  • This helps reduce code duplication and makes it easier to manage changes. If the base class changes, those updates can be applied to all the derived classes.
  • When designing your classes, think about which behaviors should be shared and what can be extended.
  • Good use of inheritance keeps your code efficient, organized, and easier to maintain. 
  • Inheritance is a key tool for creating scalable and flexible software systems.
Inheritance

Example


#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "This animal is eating." << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "The dog is barking." << endl;
    }
};

int main() {
    Dog myDog;
    myDog.eat();
    myDog.bark();
    return 0;
}
            

using System;

class Animal
{
    public void Eat()
    {
        Console.WriteLine("This animal is eating.");
    }
}

class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("The dog is barking.");
    }
}

class Program
{
    static void Main()
    {
        Dog myDog = new Dog();
        myDog.Eat();
        myDog.Bark();
    }
}
            

class Animal:
    def eat(self):
        print("This animal is eating.")

class Dog(Animal):
    def bark(self):
        print("The dog is barking.")

my_dog = Dog()
my_dog.eat()
my_dog.bark()
            

class Animal {
    void eat() {
        System.out.println("This animal is eating.");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("The dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat();
        myDog.bark();
    }
}
            

class Animal {
    eat() {
        console.log("This animal is eating.");
    }
}

class Dog extends Animal {
    bark() {
        console.log("The dog is barking.");
    }
}

const myDog = new Dog();
myDog.eat();
myDog.bark();
            

Output


This animal is eating.
The dog is barking.
    

Explanation

  • In this code, we have an Animal class with an eat() method that shows a message. 
  • The dog class inherits from animals, so it can use the eat() method and has its own bark() method. 
  • In the main function, we create a Dog object, make it eat, and then make it bark to show both actions.

Polymorphism

  • Polymorphism is like giving different objects the ability to respond to the same action in their own way.
  • It allows you to use a single method name or interface, but each object can implement its own behavior.
  • With polymorphism, you can write flexible code where different types of objects are handled through a common interface or method, yet each object can do something unique.
  • This reduces complexity and makes it easier to extend or change parts of your program without affecting the whole system.
  • When designing your classes, think about how objects with shared behaviors can respond differently to the same method.
  • Good use of polymorphism keeps your code adaptable and easier to maintain, making your software more flexible and powerful.
Polymorphism

Example


#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() {
        cout << "The animal makes a sound." << endl;
    }
};

class Cat : public Animal {
public:
    void sound() override {
        cout << "The cat meows." << endl;
    }
};

class Dog : public Animal {
public:
    void sound() override {
        cout << "The dog barks." << endl;
    }
};

int main() {
    Animal* myAnimal = new Animal();
    Animal* myCat = new Cat();
    Animal* myDog = new Dog();

    myAnimal->sound();
    myCat->sound();
    myDog->sound();

    delete myAnimal;
    delete myCat;
    delete myDog;

    return 0;
}
            

using System;

class Animal
{
    public virtual void Sound()
    {
        Console.WriteLine("The animal makes a sound.");
    }
}

class Cat : Animal
{
    public override void Sound()
    {
        Console.WriteLine("The cat meows.");
    }
}

class Dog : Animal
{
    public override void Sound()
    {
        Console.WriteLine("The dog barks.");
    }
}

class Program
{
    static void Main()
    {
        Animal myAnimal = new Animal();
        Animal myCat = new Cat();
        Animal myDog = new Dog();

        myAnimal.Sound();
        myCat.Sound();
        myDog.Sound();
    }
}
            

class Animal:
    def sound(self):
        print("The animal makes a sound.")

class Cat(Animal):
    def sound(self):
        print("The cat meows.")

class Dog(Animal):
    def sound(self):
        print("The dog barks.")

my_animal = Animal()
my_cat = Cat()
my_dog = Dog()

my_animal.sound()
my_cat.sound()
my_dog.sound()
            

abstract class Animal {
    void sound() {
        System.out.println("The animal makes a sound.");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("The cat meows.");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("The dog barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        Animal myCat = new Cat();
        Animal myDog = new Dog();

        myAnimal.sound();
        myCat.sound();
        myDog.sound();
    }
}
            

class Animal {
    sound() {
        console.log("The animal makes a sound.");
    }
}

class Cat extends Animal {
    sound() {
        console.log("The cat meows.");
    }
}

class Dog extends Animal {
    sound() {
        console.log("The dog barks.");
    }
}

const myAnimal = new Animal();
const myCat = new Cat();
const myDog = new Dog();

myAnimal.sound();
myCat.sound();
myDog.sound();
            

Output


The animal makes a sound.
The cat meows.
The dog barks.
    

Explanation

  • The Animal class has a virtual method sound, which provides a default message indicating that the animal makes a sound.
  • The Cat class inherits from Animal and overrides the sound method to output "The cat meows."
  • The Dog class also inherits from Animal and overrides the sound method to output "The dog barks."
  • In the main function, three pointers of type Animal are created, each pointing to instances of Animal, Cat, and Dog.
  • When calling the sound method on each pointer, the program demonstrates polymorphism: the correct overridden method is executed based on the actual object type.
  • Finally, the program cleans up by releasing the dynamically allocated memory for each object using delete.

Dynamic Binding

  • Dynamic binding is similar to making decisions about which method to run at the last moment during runtime.
  • Instead of determining which technique will be utilized when the code is created, the decision is made when the program is executed.
  • This provides greater versatility, particularly when dealing with inheritance and polymorphism.
  • Dynamic binding allows the computer to select which method to call based on the object type rather than the reference type, guaranteeing that the proper version of a method is executed.
  • This allows you to develop more flexible and reusable code, as objects can change behavior even when accessed using common references.
  • When using dynamic binding, think about how methods can be overridden in derived classes to provide specific functionality while still sharing a common interface. It makes your code more adaptable and allows for smoother extensions and updates.

Message Passing

  • Message passing allows things to communicate with one another by sending and receiving messages.
  • It's similar to how people talk to each other to share information or ask for assistance.
  • In programming, when one object needs to interact with another, it sends a message to request an action or share data.
  • Think of it like sending a text message to a friend: you tell them what you want or need, and they answer accordingly.
  • In object-oriented programming, message passing enables objects to request methods or properties from other objects, resulting in better-ordered and modular code.

For example, if you have a Car class and another called Driver, the Driver can send a message to the Car instructing it to start or stop. This way, the Driver does not need to understand how the Car operates internally. It simply sends a message to accomplish an action. This technique makes your code easier to comprehend and maintain because each object may focus on its own job while working with others.

Why is object-oriented programming required?

  • Object-oriented programming (OOP) is important because it helps you organize code in a way that is easier to manage and understand.
  • By using objects, you can create reusable code, which saves time and effort.
  • OOP also makes it simpler to model real-world situations, allowing you to solve problems more intuitively.
  • Additionally, it promotes better collaboration among developers and enhances code maintainability, making it easier to update and extend applications over time.
OOPs Interview Questions and Answers
Summary

Object-Oriented Programming (OOP) helps you organize your code in a way that is easy to manage and understand. It is like building with reusable blocks, making it quicker to create and modify applications. OOP also helps you model real-world situations, allowing you to solve problems more naturally. Plus, it makes it easier for you to work with others and update your code over time. By using object-oriented programming (OOP) conceptsScholarhat offers training programs such as C programmingCPPC#Java, and Python. You can enroll in any one of them and kickstart your career.

FAQs

Object-oriented programming (OOP) allows objects to communicate with one another by utilizing four fundamental principles: encapsulation, inheritance, polymorphism, and abstraction.

The concept of objects underpins object-oriented programming. Data structures, or objects, are defined in object-oriented programming, each with its own set of traits or attributes. Each object can also have its own set of processes or methods. Objects that interact with one another are used to create software.

A class is a blueprint for constructing objects (a specific data structure), giving starting settings for the state (member variables or attributes), and implementing behavior (member functions or methods) in object-oriented programming. The class keyword is used to build user-defined objects.

Object Oriented Programming System is the full form of OOPS.

Encapsulation is a method for restricting direct access to some components of an object so that users cannot get state values for all variables of a specific object. Encapsulation can be used to conceal both data members and data functions or methods associated with a class or object that has been instantiated.
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan is the Founder and CEO at ScholarHat by DotNetTricks which is a brand when it comes to e-Learning. He provides training and consultation over an array of technologies like Cloud, .NET, Angular, React, Node, Microservices, Containers and Mobile Apps development. He has been awarded Microsoft MVP 9th time in a row (2016-2024). He has changed many lives with his writings and unique training programs. He has a number of most sought-after books to his name which has helped job aspirants in cracking tough interviews with ease.
Accept cookies & close this