Object Oriented Programming in C++.

Object-Oriented Programming (OOP) is a programming paradigm that organizes and structures code around the concept of "objects," which are self-contained units containing both data and behavior. In OOP, objects represent real-world entities, and the programming revolves around interactions between these objects.


The core principles of Object-Oriented Programming are:

  • Encapsulation.
  • Abstraction.
  • Inheritance.
  • Polymorphism.
We are going to cover all these principles in detail with real-life examples in this post but before understanding them there are a few important terms that we need to understand. 

Class

In C++, a class is a user-defined data type that serves as a blueprint for creating objects. It encapsulates data (attributes) and methods (member functions) that operate on that data. Classes enable developers to model real-world entities, organize code, and implement the principles of Object-Oriented Programming (OOP).

Object

In C++, an object is a concrete instance of a class. It is a self-contained unit that combines data (attributes) and behavior (methods) defined in the class blueprint. Objects represent real-world entities and can interact with each other through their methods and attributes.

Let's take a real-world example to understand the concept of class and object and how it works.

Example: Consider we have a class name Vehicle, the Vehicle class contains attributes like Brand, Model, Color, and Fuel Type. It also has some properties like ChangeGear(), GetFuelLevel(), Accelerate(), and Brake(). Using this Vehicle class as a blueprint, we can create multiple vehicle objects, each with its own unique set of attributes and behavior. 

C++ Example Code:
//C++ Example Code to show working of Class and Objects
#include <iostream>
#include <string>
using namespace std;

class Car {
public:
    // Attributes
    string brand;
    string model;
    string color;
    string fuelType;

    // Methods
    void ChangeGear() {
        cout << "The " << brand << " " << model << " is changing Gear...\n";
    }

    void Accelerate() {
        cout << "The " << brand << " " << model << " is accelerating...\n";
    }

    void Brake() {
        cout << "The " << brand << " " << model << " is braking...\n";
    }
};

int main() {
    // Creating car objects using the Car class
    Car car1;

    car1.brand = "Toyota";
    car1.model = "Camry";
    car1.color = "Blue";
    car1.fuelType = "Petrol";

    car1.ChangeGear();
    car1.Accelerate();
    car1.Brake();

    return 0;
}
Output:
The Toyota Camry is changing Gear...
The Toyota Camry is accelerating...
The Toyota Camry is braking...
The memory required to hold the object's data (attributes) and the code for its methods (member functions) is allocated from the computer's memory.(alert-success)

I hope till now you have understood the two most important terms of OOPs that is class and object. Now we are going to explore the core principles of OOPs one by one.


Encapsulation

Encapsulation is the concept of bundling data and methods within a class, hiding internal implementation details from the outside world. It allows for data abstraction and provides access control through public, private, and protected access specifiers. You can read more about Access Specifiers here.


Example: In the Car class, the attributes (make, model, year) may be declared as private, ensuring that they can only be accessed and modified through public methods like getMake() and setMake(). This way, the internal state of the car object is encapsulated and protected.


Example Code:

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

class Car {
private:
    string make;
    string model;
    int year;

public:
    // Constructor
    Car(string carMake, string carModel, int carYear) {
        make = carMake;
        model = carModel;
        year = carYear;
    }

    // Getter methods
    string getMake() const {
        return make;
    }
    string getModel() const {
        return model;
    }
    int getYear() const {
        return year;
    }

    // Setter methods
    void setMake(string newMake) {
        make = newMake;
    }
    void setModel(string newModel) {
        model = newModel;
    }
    void setYear(int newYear) {
        year = newYear;
    }
};

int main() {
    // Creating a Car object using the constructor
    Car myCar("Toyota", "Camry", 2022);

    // Using the setter methods to modify attributes
    myCar.setMake("Honda");
    myCar.setModel("Civic");
    myCar.setYear(2021);

    // Displaying the updated car details
    cout << "\nUpdated Car Details:" << endl;
    cout << "Make: " << myCar.getMake() << endl;
    cout << "Model: " << myCar.getModel() << endl;
    cout << "Year: " << myCar.getYear() << endl;

    return 0;
}
Output:
Updated Car Details:
Make: Honda
Model: Civic
Year: 2021

Access specifiers are keywords used in class definitions to control the visibility and accessibility of class members (attributes and methods) from outside the class. (alert-success) 


Abstraction

Abstraction involves representing essential features and behavior of objects while hiding unnecessary details. It allows us to focus on what an object does rather than how it does it.

Abstraction is achieved in C++ through the use of classes and access specifiers (public, private, protected). The public interface of the class represents the abstraction, while the private and protected sections hide the implementation details from external code. 

Example: In a banking application, a BankAccount class may provide methods like deposit(), withdraw(), and getBalance(), abstracting away the complex internal banking operations and exposing only the essential functionality needed by users.


Inheritance

Inheritance is a mechanism that allows a class to inherit properties and behaviors from another class, forming a hierarchical relationship. The derived class (child class) inherits the characteristics of the base class (parent class).
Inheritance allows for code reuse, as the derived class can reuse the properties and behaviors of the base class, eliminating the need to rewrite common code.(alert-success)

They are classified into various types based on the hierarchy and relationships between classes and these are:

  • Single Inheritance: A derived class inherits from only one base class. 
  • Multiple Inheritance: A derived class can inherit from two or more base classes.
  • Multilevel Inheritance: A derived class inherits from another derived class, creating a chain of inheritance.
  • Hierarchical Inheritance: Multiple derived classes inherit from a single base class.
  • Hybrid (or Virtual) Inheritance: A combination of multiple and multilevel inheritance.

Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common base class. It enables the same method to be implemented in different ways in different classes, based on their specific behavior.

Example: Using the vehicle hierarchy, a generic method like drive() can be defined in the base class Vehicle. Each derived class (Car, Motorcycle, Truck) can provide its own implementation of the drive() method based on the unique way each vehicle type operates.

Fixed Size Sliding Window Algorithm with Example.

The Fixed Size Sliding Window Algorithm is a powerful technique used in computer programming and data processing to efficiently process data in a sliding window fashion. This algorithm is particularly useful when dealing with large data sets or solving problems involving continuous or sequential data processing.


Here in this article, we are going to cover Fixed-Size Sliding Window Algorithm in detail with Example.  


When to use Fixed Size Sliding Window Algorithm? 

The Fixed Size Sliding Window Algorithm is particularly useful in scenarios where you need to efficiently process sequential data by maintaining a fixed-size subset or window of elements. 


Here are some situations where this algorithm can be beneficial:

  • Subarray/Substring Problems: When you need to solve problems that involve finding the maximum or minimum sum, product, or average of a contiguous subarray or substring within a larger array or string.
  • Sequential Data Processing: When you need to process data in a sequential manner, such as time series data, sensor readings, or log files, and perform calculations or computations on a fixed-size subset of the data.
  • Windowed Aggregations: When you need to compute aggregate values (e.g., sum, average, maximum, minimum) over a sliding window of elements in a time-based or sequential data stream.
  • Pattern Matching: When you need to identify or search for specific patterns or sequences within a larger sequence or stream of data.

Algorithm of Fixed Size Sliding Window.

The Fixed Size Sliding Window Algorithm involves maintaining a fixed-size window or subset of elements as it slides through the input data. The window moves one element at a time, allowing for efficient data processing and analysis. 


The algorithm typically follows these steps:


Step 1: Initialize the window with the first 'k' elements from the input data, where 'k' is the desired window size.

Step 2: Process the initial window to perform any required calculations or operations.

Step 3: Slide the window by moving one element forward.

Step 4: Update the window by adding the next element from the input data and removing the last element from the previous window.

Step 5: Perform the necessary computations or operations on the updated window.

Step 6: Repeat steps 3-5 until the end of the input data is reached.


So these are steps that you need to follow to solve any fixed-size sliding window problem, let's understand the algorithm in more detail with one example.


Example of Fixed Size Sliding Window.

Given an array of size n, we need to find the maximum sum of k consecutive elements in the array. 

Example:

Input: num[] = {2, 3, 5, 4, 9, 7, 1}  k = 3
Output: 20

Explanation: 
The sum of all possible subarrays of size 3
{2, 3, 5} = 2+3+5 = 10
{3, 5, 4} = 3+5+4 = 12
{5, 4, 9} = 5+4+9 = 18
{4, 9, 7} = 4+9+7 = 20
{9, 7, 1} = 9+7+1 = 17 
The maximum sum we get by adding the subarray {4, 9, 7} of size 3.

Step by Step Algorithm to solve the above problem using Fixed Size Sliding Window Approach:

Step 1: Start with the given input array nums and the window size k.
Step 2: Initialize variables windowSum and maxSum to 0.
Step 3: Calculate the initial window sum by iterating from index 0 to k-1 and adding each element to windowSum.
Step 4: Assign the value of windowSum to maxSum.
Step 5: Iterate from index k to nums.size() - 1:
  • Add the current element at index i to windowSum.
  • Subtract the element at index i-k (the element that leaves the window) from windowSum.
  • Update maxSum by taking the maximum value between maxSum and windowSum.
Step 6: After the iteration, the value of maxSum will hold the maximum sum of 'k' consecutive elements in the array nums.
Step 7: Return maxSum.

Here is the C++ Code Implementation:
//C++ Program to Find Max Sum of Window Size K
#include <iostream>
#include <vector>
using namespace std;

int maxSumInSlidingWindow(const vector<int>& nums, int k) {
    int windowSum = 0;
    int maxSum = 0;

    // Calculate the initial window sum
    for (int i = 0; i < k; ++i) {
        windowSum += nums[i];
    }

    maxSum = windowSum;

    // Slide the window and update the maximum sum
    for (int i = k; i < nums.size(); ++i) {
        windowSum += nums[i] - nums[i - k];
        maxSum = max(maxSum, windowSum);
    }

    return maxSum;
}

int main() {
    vector<int> nums = {2, 3, 5, 4, 9, 7, 1};
    int k = 3;

    int maxSum = maxSumInSlidingWindow(nums, k);

    cout << "Maximum sum of " << k << " consecutive elements: " << maxSum << endl;

    return 0;
}
Output:
Maximum sum of 3 consecutive elements: 20
  • Time ComplexityThe time complexity of the algorithm is O(N), where N represents the number of elements in the input array nums.
  • Space ComplexityThe space complexity of the algorithm is O(1) since it uses a constant amount of additional space.

The Fixed Size Sliding Window Algorithm offers several advantages, including reduced memory usage, faster processing times, and the ability to solve problems that require analyzing a subset of sequential data.

Zeller's Congruence algorithm | Find the Day for a Date.

Zeller's Congruence algorithm is a mathematical formula that can be used to determine the day of the week for a given date. It was developed by Christian Zeller in the late 19th century and provides a straightforward calculation based on the day, month, and year.


The algorithm takes advantage of a modified calendar where January and February are considered months 13 and 14 of the previous year. This adjustment simplifies the calculation and allows for consistent formulas across all months.


The formula used in Zeller's Congruence algorithm is as follows:

h = (day + (13 * (month + 1)) / 5 + yearOfCentury + yearOfCentury / 4 + century / 4 + 5 * century) % 7

Where:
  • h is the calculated day of the week (0 - Saturday, 1 - Sunday, ..., 6 - Friday).
  • day is the day of the month (1 to 31).
  • month is the month of the year (3 to 14, with January and February adjusted as 13 and 14 respectively).
  • year is the year (e.g., 2023).
  • century is the century part of the year (e.g., 20 for the year 2023).
  • yearOfCentury is the year within the century (e.g., 23 for the year 2023).

The formula calculates a value of h, which represents the day of the week. To map this value to the corresponding day of the week, you can use the following mapping:
  • 0: Saturday
  • 1: Sunday
  • 2: Monday
  • 3: Tuesday
  • 4: Wednesday
  • 5: Thursday
  • 6: Friday

By applying Zeller's Congruence algorithm, you can determine the day of the week for any given date, enabling you to perform various date-related calculations and manipulations in programming.

C++ Program to Find the Day for a Date.

Example code:
//C++ Program Find the Day for a Date
#include <iostream>
using namespace std;

int getDayOfWeek(int day, int month, int year) {
    if (month == 1 || month == 2) {
        month += 12;
        year--;
    }

    int century = year / 100;
    int yearOfCentury = year % 100;

    int h = (day + (13 * (month + 1)) / 5 + yearOfCentury + yearOfCentury / 4 + century / 4 + 5 * century) % 7;

    return h;
}

int main() {
    int day, month, year;

    cout << "Enter the date (DD MM YYYY): ";
    cin >> day >> month >> year;

    int dayOfWeek = getDayOfWeek(day, month, year);

    switch (dayOfWeek) {
        case 0:
            cout << "Saturday\n";
            break;
        case 1:
            cout << "Sunday\n";
            break;
        case 2:
            cout << "Monday\n";
            break;
        case 3:
            cout << "Tuesday\n";
            break;
        case 4:
            cout << "Wednesday\n";
            break;
        case 5:
            cout << "Thursday\n";
            break;
        case 6:
            cout << "Friday\n";
            break;
        default:
            cout << "Invalid day of the week\n";
            break;
    }

    return 0;
}
Output:
Enter the date (DD MM YYYY): 12 06 2023
Monday

C Program to Display Complete Calendar for Given Year.

In this article, we will explore how to write a C program to display a month-by-month calendar for a given year. The program will calculate the number of days in each month and determine the day of the week for the first day of each month. Using this information, it will print a formatted calendar for each month, including the corresponding day of the week for each date.


Steps to Display a month-by-month calendar for a given year:


Step 1: Accept the input year from the user.

Step 2: Define functions to calculate the number of days in a month and the day of the week for the first day of a given month.

Step 3: Iterate through each month of the year and generate the calendar for each month.

Step 4: Format and display the calendar for each month, including the month name and the corresponding day of the week for each date.

Step 5: Repeat the above steps for all twelve months of the year.


Code Example:

//C Program to print month by month calendar for given year
#include <stdio.h>

//function to check leap year
int isLeapYear(int year) {
    if (year % 400 == 0)
        return 1;
    if (year % 100 == 0)
        return 0;
    if (year % 4 == 0)
        return 1;
    return 0;
}

//function to get the number of day in that month
int getNumberOfDays(int month, int year) {
    int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    if (month == 2 && isLeapYear(year))
        return 29;
    else
        return daysInMonth[month - 1];
}

//
int getDayOfWeek(int day, int month, int year) {
    int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    if (month < 3)
        year--;

    int dayOfWeek = (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;

    return dayOfWeek;
}

void displayCalendar(int year) {
    char *months[] = {"January", "February", "March", "April", "May", "June",
                      "July", "August", "September", "October", "November", "December"};

    for (int month = 1; month <= 12; month++) {
        int days = getNumberOfDays(month, year);
        int firstDayOfWeek = getDayOfWeek(1, month, year);

        printf("\n--------------- %s ---------------\n", months[month - 1]);
        printf("Sun Mon Tue Wed Thu Fri Sat\n");

        int day;
        for (int space = 0; space < firstDayOfWeek; space++)
            printf("    ");
        for (day = 1; day <= days; day++) {
            printf("%3d ", day);
            if ((day + firstDayOfWeek) % 7 == 0)
                printf("\n");
        }
        if ((day + firstDayOfWeek) % 7 != 0)
            printf("\n");
    }
}

int main() {
    int year;

    printf("Enter the year: ");
    scanf("%d", &year);

    displayCalendar(year);

    return 0;
}
Output:
Enter the year: 2023
--------------- January ---------------
Sun Mon Tue Wed Thu Fri Sat
  1   2   3   4   5   6   7 
  8   9  10  11  12  13  14 
 15  16  17  18  19  20  21 
 22  23  24  25  26  27  28 
 29  30  31 

--------------- February ---------------
Sun Mon Tue Wed Thu Fri Sat
              1   2   3   4 
  5   6   7   8   9  10  11 
 12  13  14  15  16  17  18 
 19  20  21  22  23  24  25 
 26  27  28 

--------------- March ---------------
Sun Mon Tue Wed Thu Fri Sat
              1   2   3   4 
  5   6   7   8   9  10  11 
 12  13  14  15  16  17  18 
 19  20  21  22  23  24  25 
 26  27  28  29  30  31 
--------------- April ---------------
Sun Mon Tue Wed Thu Fri Sat
                          1 
  2   3   4   5   6   7   8 
  9  10  11  12  13  14  15 
 16  17  18  19  20  21  22 
 23  24  25  26  27  28  29 
 30 

--------------- May ---------------
Sun Mon Tue Wed Thu Fri Sat
      1   2   3   4   5   6 
  7   8   9  10  11  12  13 
 14  15  16  17  18  19  20 
 21  22  23  24  25  26  27 
 28  29  30  31 

--------------- June ---------------
Sun Mon Tue Wed Thu Fri Sat
                  1   2   3 
  4   5   6   7   8   9  10 
 11  12  13  14  15  16  17 
 18  19  20  21  22  23  24 
 25  26  27  28  29  30 
--------------- July ---------------
Sun Mon Tue Wed Thu Fri Sat
                          1 
  2   3   4   5   6   7   8 
  9  10  11  12  13  14  15 
 16  17  18  19  20  21  22 
 23  24  25  26  27  28  29 
 30  31 

--------------- August ---------------
Sun Mon Tue Wed Thu Fri Sat
          1   2   3   4   5 
  6   7   8   9  10  11  12 
 13  14  15  16  17  18  19 
 20  21  22  23  24  25  26 
 27  28  29  30  31 

--------------- September ---------------
Sun Mon Tue Wed Thu Fri Sat
                      1   2 
  3   4   5   6   7   8   9 
 10  11  12  13  14  15  16 
 17  18  19  20  21  22  23 
 24  25  26  27  28  29  30 


--------------- October ---------------
Sun Mon Tue Wed Thu Fri Sat
  1   2   3   4   5   6   7 
  8   9  10  11  12  13  14 
 15  16  17  18  19  20  21 
 22  23  24  25  26  27  28 
 29  30  31 

--------------- November ---------------
Sun Mon Tue Wed Thu Fri Sat
              1   2   3   4 
  5   6   7   8   9  10  11 
 12  13  14  15  16  17  18 
 19  20  21  22  23  24  25 
 26  27  28  29  30 

--------------- December ---------------
Sun Mon Tue Wed Thu Fri Sat
                      1   2 
  3   4   5   6   7   8   9 
 10  11  12  13  14  15  16 
 17  18  19  20  21  22  23 
 24  25  26  27  28  29  30 
 31 

  • Time Complexity: The time complexity of the code can be considered as O(1) since the majority of the operations involve constant time complexity.
  • Space Complexity: The space complexity of the code is constant or O(1).

Difference Between Git Fetch and Git Pull Command.

When we work with Git, it's essential to comprehend the distinctions between common commands to effectively manage and synchronize our codebase. Two commands often used for retrieving updates from a remote repository are git pull and git fetch.


What is the git fetch command?

The git fetch command is used in Git to retrieve new commits, branches, and tags from a remote repository without automatically merging or modifying our current branch. It allows us to fetch the latest changes from the remote repository and update our local repository's references, keeping them in sync with the remote repository.


When we run git fetch, Git contacts the remote repository specified by the remote URL (usually origin) and retrieves any new commits or branches that exist in the remote repository but not in our local repository. It updates the remote-tracking branches in our local repository to reflect the state of the remote repository.


Here's a step-by-step example of using the git fetch command:


Step 1: Initialize a Git Repository

Create a new directory and navigate into it.

mkdir my-repo
cd my-repo

Initialize a new Git repository:
git init

Step 2: Add a Remote Repository
Add a remote repository as the upstream source. Replace <remote-url> with the URL of the remote repository.
git remote add origin <remote-url>

Step 3: Fetch Remote Changes
Run the git fetch command to retrieve the latest changes from the remote repository.
git fetch

This command contacts the remote repository and fetches any new commits, branches, or tags that exist in the remote repository but not in our local repository. The remote-tracking branches in our local repository will be updated to reflect the state of the remote repository.

What is the git pull command?

The git pull command in Git is used to update our current branch with the latest changes from a remote repository and automatically merge them into our local branch. It combines two actions into one step: fetching the changes from the remote repository and merging them into our branch.

When we run git pull, Git first contacts the remote repository specified by the remote URL (usually origin) and retrieves the new commits and branches that exist in the remote repository but not in our local repository. It performs a git fetch internally to update our remote-tracking branches.

After fetching the changes, git pull automatically merges them into our current branch. If there are no conflicts, Git will create a new commit that incorporates the remote changes into our local branch's history. If conflicts arise, Git will prompt us to resolve them before completing the merge.

git pull origin master

We pull the changes from the master branch of the remote repository named origin. We can Adjust the branch name and remote repository as needed.

Key differences between git pull and git fetch.

Git Fetch Git Pull
Does not automatically merge the retrieved changes. Automatically merges the retrieved changes into the current branch, potentially resulting in a new commit.
Preserves the local working copy's state and does not modify it. Automatically modifies the workspace by incorporating the retrieved changes, potentially leading to conflicts.
Safer as it allows you to review changes before merging and provides more control over the merging process. Automates the merging process and may lead to conflicts without prior review.
Ideal in collaborative environments, enabling you to stay up-to-date with the latest changes and review them separately. Convenient for quickly integrating updates into the local working copy, assuming trust in the remote repository's changes.

Use Cases of Git Fetch and Git Pull.

Understanding the appropriate use cases for each command is crucial:
Use git fetch when you want to inspect the changes made by others before merging them into your branch. It allows you to review and resolve conflicts, ensuring a smooth integration process. (alert-success)
Use git pull when you trust the changes made in the remote repository and want to automatically merge them into your branch. This is convenient for quickly incorporating updates into your local working copy. (alert-success)

By utilizing these commands appropriately, you can efficiently manage your codebase, stay up-to-date with remote changes, and streamline your collaboration efforts in Git. 

DON'T MISS

Tech News
© all rights reserved
made with by AlgoLesson