Open In App

Object Model | Object Oriented Analysis & Design

Last Updated : 27 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Object-Oriented Programming (OOP) is a fundamental paradigm in modern software development that has transformed the way we design, build, and maintain software systems. OOP is centered around the concept of objects, which are self-contained, reusable units that encapsulate both data and the operations that can be performed on that data. This approach mirrors real-world modeling, making it easier to understand, manage, and expand software projects.

Objects and Classes

What is a Class?

A class is a blueprint or a user-defined data type that defines the structure and behavior of objects. It acts as a template for creating objects. Classes encapsulate data (attributes) and the methods (functions) that operate on that data. Think of a class as a recipe for creating objects with specific attributes and behaviors.

Here’s a simple example of a class definition in C++:

C++




class Car {
public:
    // Attributes
    std::string brand;
    int year;
    float price;
 
    // Methods
    void startEngine()
    {
        std::cout << "Engine started!" << std::endl;
    }
    void stopEngine()
    {
        std::cout << "Engine stopped!" << std::endl;
    }
};


In this example, we’ve defined a Car class with attributes (brand, year, price) and methods (startEngine, stopEngine).

Creating Objects

Once a class is defined, you can create objects (also known as instances) of that class. Objects are concrete entities based on that class’s blueprint. To create on object, you use the class name followed by the object name:

C++




int main()
{
    // Create objects of the Car class
    Car myCar; // Object 1
    Car yourCar; // Object 2
 
    // Set attributes for myCar
    myCar.brand = "Toyota";
    myCar.year = 2022;
    myCar.price = 25000;
 
    // Access methods
    myCar.startEngine();
 
    // Set attributes for yourCar
    yourCar.brand = "Honda";
    yourCar.year = 2023;
    yourCar.price = 27000;
 
    // Access methods
    yourCar.startEngine();
    yourCar.stopEngine();
 
    return 0;
}


Here, we’ve created two Car objects myCar and yourCar, and accessed their attributes and methods. Each object has its own set of attributes and can have its methods called independently.

Encapsulation and Data Hiding

Encapsulation and Data Hiding are two fundamental principles of object-oriented programming.

Encapsulation

Encapsulation is the concept of bundling data (attributes or variables) and the methods (functions) that operate on that data into a single unit called a class. It restrict access to some of an object’s components, providing a way to control and protect data from external inteference. Encapsulation helps achieve data abstraction and maintain the integrity of an object’s state.

To implement encapsulation in C++:

  • Define a class: Define a class that encapsulates data and methods related to a specific conecpt or entity.
  • Use Access Specifiers: Use access specifiers like private, public and protected to control the visibility and accessibility of class members. Private members are only accessible within the class, while public members are accessible from outside the class.

Below is the example implementation for the above topic

C++




class Car {
private:
    int speed;
    int fuelLevel;
 
public:
    // Constructor
    Car(int initialSpeed, int initialFuelLevel)
    {
        speed = initialSpeed;
        fuelLevel = initialFuelLevel;
    }
 
    // Public methods for accessing and modifying data
    void SetSpeed(int newSpeed) { speed = newSpeed; }
 
    int GetSpeed() { return speed; }
 
    // Other methods for the class
};


Data Hiding

Data Hiding is a curical aspect of encapsulation. It invokes making data members (variables) private so that they cannot be accessed directly from outside the class. Instead, you provide controlled access to the data through public member functions (getters and setters).

To implement data hiding in C++:

  • Make data members private: Declare data members as private within the class, preventing direct access from outside.
  • Provide getter and setter methods: Create public members functions (getters and setters) that allow controlled access to the private data members.

Below is the example implementation for the above topic:

C++




class Car {
private:
    int speed;
    int fuelLevel;
 
public:
    // Constructor
    Car(int initialSpeed, int initialFuelLevel)
    {
        speed = initialSpeed;
        fuelLevel = initialFuelLevel;
    }
 
    // Public methods for accessing and modifying data
    void SetSpeed(int newSpeed) { speed = newSpeed; }
 
    int GetSpeed() { return speed; }
};


Message Passing

Message Passing is a fundamental conecpt in computer science and programming especially in the context of concurrent and distributed systems. It refers to a method of communication between different processes or objects, where they exchange information by sending and receiving messages. This enables the synchronization and cooordination of activities in a multi-threaded or distributed environment.

In C++, message passing can be implemented using various mechanisms, such as threads, inter-process communication (IPC), or librariesl like MPI (Message Passing Interface) for distributed memory systems.

Inheritance

Inheritance is a fundamental concept in object-oriented programming (OOP), and it allows you to create a new class that is based on an existing class. This existing class is referred as the base class or parent class and the new class is called the derived class or child class. Inheritance facilitates code reusability and the creation of a hierarchical structure for classes.

In C++, there are different types of inheritance:

  1. Single Inheritance: In single inheritance, a derived class inherits from a single class.
  2. Multiple Inheritance: In multiple inheritance, a derived class can inherit from multiple base classes.
  3. Multilevel Inheritance: In multilevel inheritance, a class inherits from a base class, and then another class inherits from the derived classs, creating a chain.
  4. Hierarchical Inheritance: In hierarchical inheritance, multiple classes inherit from a single base class.
  5. Hybrid Inheritance: Hybrid Inheritance is a combination of two or more types of inheritance.

Here’s an example in C++ that demonstrates single inheritance:

C++




#include <iostream>
 
// Base class (Parent class)
class Animal {
public:
    void eat()
    {
        std::cout << "Animal is eating." << std::endl;
    }
 
    void sleep()
    {
        std::cout << "Animal is sleeping." << std::endl;
    }
};
 
// Derived class (Child class)
class Dog : public Animal {
public:
    void bark()
    {
        std::cout << "Dog is barking." << std::endl;
    }
};
 
int main()
{
    Dog myDog;
 
    myDog.eat(); // Inherited from Animal
    myDog.sleep(); // Inherited from Animal
    myDog.bark(); // Part of Dog class
 
    return 0;
}


Output

Animal is eating.
Animal is sleeping.
Dog is barking.

This is a simple example of single inheritance in C++. The Dog class inherits the properties and behaviors of Animal class and can also have its own additional members. This code structure promotes code reuse and the modeling of relationships between different classes in a hierarchical manner.

Polymorphism

Polymorphism derived from Greek word poly (many) and morphe (form) means many forms. In C++, Polymorphism allows different classes to be treated uniformly through a common base class. This concept is divited into two types: complie time (static) polymorphism and runtime (dynamic) polymorphism.

Compile Time Polymorphism (Static Polymorphism)

  • Also known as early binding or method overloading.
  • Occurs at compile time, when the compiler determines which function or method to call based on the number and types of arguments.
  • Typically achieved through function overloading and operator overloading.

Example: Consider a simple calculator that needs to perform addition for various data types (int, double, and float). Instead of creating separate functions for each data type, you can use compile-time polymorphism by overloading the addtion operator.

C++




class Calculator {
public:
    int add(int a, int b) { return a + b; }
 
    double add(double a, double b) { return a + b; }
 
    float add(float a, float b) { return a + b; }
};


In this example, the add fucntion is overloaded to handle different data types, allowing you to use a single function name for addition operations.

Runtime Polymorphism (Dynamic Polymorphism)

  • Also known as late binding.
  • Occurs at runtime, where the specific function to be executed is determined dynamically based on the object’s actual type.
  • Achieved through virtual functions and inheritance.

Example: Imagine a university management system with various staff members like professors and administrative staff. Both have a common method called displayInfo, but the way they display their information is different. You can use runtime polymorphism by creating a base class and derived classses.

C++




class Staff {
public:
    virtual void displayInfo()
    {
        std::cout << "Base class: Staff" << std::endl;
    }
};
 
class Professor : public Staff {
public:
    void displayInfo() override
    {
        std::cout << "Derived class: Professor"
                  << std::endl;
    }
};
 
class AdministrativeStaff : public Staff {
public:
    void displayInfo() override
    {
        std::cout << "Derived class: Administrative Staff"
                  << std::endl;
    }
};


In this example, the Staff class has a virtual function displayInfo. When you call this function on objects on the derived classes, the appropriate version of displayInfo is invoked based on the acutal type of the object.

Generalization and Specialization

Generalization and Specialization are two complementary processes that allow the creation of class hierarchies.

Generalization

Generalization involves creating a base or parent class (superclass) that defines common attributes and behaviors shared by multiple derived or child classes (subclasses). The base class captures the common features, and the derived classes add specialized features.

Specialization

Specialization on the other hand, focuses on the derived classes that inherit from a common base class. These subclasses provide specific details, attributes, or behaviors that differentiate them from the others while retaining the shared characteristics.

Let’s use an example to understand – modeling different types of animals. We will have a base class Animal representing shared properties and behaviors, and derived classes like Dog and Cat that specialize the general Animal class.

Below is the implementation of the above example:

C++




#include <iostream>
#include <string>
 
class Animal {
protected:
    std::string name;
 
public:
    Animal(const std::string& n)
        : name(n)
    {
    }
 
    void eat()
    {
        std::cout << name << " is eating." << std::endl;
    }
 
    virtual void makeSound()
    {
        std::cout << "An animal makes a generic sound."
                  << std::endl;
    }
};
 
class Dog : public Animal {
public:
    Dog(const std::string& n)
        : Animal(n)
    {
    }
 
    void makeSound() override
    {
        std::cout << name << " barks: Woof woof!"
                  << std::endl;
    }
 
    void fetch()
    {
        std::cout << name << " is fetching a ball."
                  << std::endl;
    }
};
 
class Cat : public Animal {
public:
    Cat(const std::string& n)
        : Animal(n)
    {
    }
 
    void makeSound() override
    {
        std::cout << name << " meows: Meow meow!"
                  << std::endl;
    }
 
    void scratch()
    {
        std::cout << name << " is scratching the furniture."
                  << std::endl;
    }
};
 
int main()
{
    Dog myDog("Rover");
    Cat myCat("Whiskers");
 
    myDog.makeSound();
    myCat.makeSound();
 
    myDog.fetch();
    myCat.scratch();
 
    return 0;
}


Output

Rover barks: Woof woof!
Whiskers meows: Meow meow!
Rover is fetching a ball.
Whiskers is scratching the furniture.

In this example:

  • The Animal class is the general or base class, encapsulating common attributes and behaviros shared by all animals.
  • The Dog and Cat classes are specialized or derived classes. They inherit from the Animal class, extending it with their specific attributes and behaviors.
  • The makeSound method is declared as virtual in the base class and overridden in the derived classes. This is a key feature of specialization, allowing each animal to make its specific sound.
  • The fetch method is specific to the Dog class, and the scratch method is specific to the Cat class. These methods demonstrate how specialization allows us to add unique behaviros to individual subclasses.

Association and Aggregation

Association

Association is a has-a relationship between two classes. It represents a more general relationship where one class is connected to another but not necessarily in a strong way.

Example:

Suppose we have two classes, Teacher and Student , and there is an association between them

Below is the implementation of the above example:

C++




#include <iostream>
#include <vector>
 
class Student {
public:
    Student(std::string name)
        : name(name)
    {
    }
 
    std::string getName() const { return name; }
 
private:
    std::string name;
};
 
class Teacher {
public:
    Teacher(std::string name)
        : name(name)
    {
    }
 
    void addStudent(const Student& student)
    {
        students.push_back(student);
    }
 
    void listStudents()
    {
        std::cout << name << " teaches: ";
        for (const Student& student : students) {
            std::cout << student.getName() << " ";
        }
        std::cout << std::endl;
    }
 
private:
    std::string name;
    std::vector<Student> students;
};
 
int main()
{
    Teacher mathTeacher("Mr. Smith");
    Student alice("Alice");
    Student bob("Bob");
 
    mathTeacher.addStudent(alice);
    mathTeacher.addStudent(bob);
 
    mathTeacher.listStudents();
 
    return 0;
}


Output

Mr. Smith teaches: Alice Bob 

In this example:

  • Teacher and Student are two classes representing a teacher and a student respectively.
  • The Teacher class has a method addStudent to associate students with a teacher.
  • An association is created by adding students to the teacher’s list.

Aggregation

Aggregation is a type of association that represnets a whole-part relationship. It implies that one one class (the whole) contians or is composed of another class (the part). Aggregation is often depicted as a diamond-shape arrow.

Let’s modify the previous example to demonstrate aggregation:

C++




#include <iostream>
#include <vector>
 
class Student {
public:
    Student(std::string name)
        : name(name)
    {
    }
 
    std::string getName() const { return name; }
 
private:
    std::string name;
};
 
class School {
public:
    School(std::string name)
        : name(name)
    {
    }
 
    void addStudent(const Student& student)
    {
        students.push_back(student);
    }
 
    void listStudents()
    {
        std::cout << "Students at " << name << ": ";
        for (const Student& student : students) {
            std::cout << student.getName() << " ";
        }
        std::cout << std::endl;
    }
 
private:
    std::string name;
    std::vector<Student> students;
};
 
int main()
{
    School mySchool("XYZ School");
    Student alice("Alice");
    Student bob("Bob");
 
    mySchool.addStudent(alice);
    mySchool.addStudent(bob);
 
    mySchool.listStudents();
 
    return 0;
}


Output

Students at XYZ School: Alice Bob 

In this updated example:

We introduced a School class, which contains a list of students. This represents an aggregation, where a school is composed of students.

Benefits of Object Model

The object model in object-oriented programming helps with:

  • Organize your code into objects.
  • Hide details (Encapsulation).
  • Reuse code.
  • Work on objects separately (Modularity).
  • Simplify by focusing on key features (Abstraction)/
  • Create new objects through Inheritance.
  • Acheive flexibility with polymorphism.

Conclusion

In this blog, we’ve covered the fundamentals of object-oriented programming (OOP). We starated with an introduction to OOP, then delved into Objects and Classes, Encapsulation, Message Passing, Inheritance, Polymorphism, Generalization and Specialization. We explored the benefits of the object model, such as code organization and reusability, with examples provided.

In essence, OOP is a powerful paradigm for creating organized, flexible, and efficient code, making software development more manageable and rewarding.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads