Object Oriented Programming
Published: 2023-05-11 06:52:29

## Introduction
The aim of this paper is to help the reader get familiar with the concepts of object oriented programming , syntax for demonstrations will be in Python.

## Basic Concepts
**Polymorphism:** This concept can be broken down into two different categories, `Run time polymorphism` and `Compile time polymorphism`, However, The basic gist of the concept is that a function can behave differently given different circumstances, Python does not support compile time polymorphism. so we'll just look at some examples for run time polymorphism.

```
class Parent():
    def __init__(self):
        pass
    def show(self):
        print("This is parent class")

class Child(Parent):
    def __init__(self):
        pass
    def show(self):
        super().show()
        print("This is child class")


child=Child()
parent=Parent()
child.show()
```

- In the example above, The `show` method in the child class overrides the show method derived from the parent class. However, if you still wish to use the parent method, you can use the `super()` method as shown in the example. It instead invokes the overriden function.

**Encapsulation:** This is the idea of wrapping data and the methods that work on data within one unit. When you look at the definitions of `Encapsulation` and `Data Hiding` online, you might find a lot of redundancies for the explanations of these two concepts. We'll just talk about encapsulation here.

```
class getArea():
    def __init__(self):
        self.length=0
        self.breadth=0

    def set_sides(self,l,b):
        self.length=l
        self.breadth=b
    
    def get_area(self):
        return self.length*self.breadth
```

- The above snippet is a good example of encapsulation, bundling up all variables and functions inside a single unit.

**Data Hiding:** We talked about `Encapsulation` before, the gist of this concept is similar. This concept deals with the security of the software. Let me demonstrate with an example.

```
class User():
    def __init__(self):
        self.username="Utsav"
        self.password="xwru3"
```

- The example above demonstrates the dangers of not hiding data that needs to stay secret, since the `username` and `password` in the above snippet are public variables anyone can change them. Let me demonstrate a better way of doing this:

```
class User():
    def __init__(self):
        self.__username="Utsav"
        self.__password="xwru3"
    def change_password(self,new_password,old_password):
        if old_password!=self.__password:
            print("The password you entered is incorrect")
            return
        self.__password=new_password
        print("Password changed successfully")
```

- The code above demonstrates how you can increase security using private methods when needed. Now you can only change the password if you know your old password.

**Abstraction:** This is the concept of only displaying the essential details to the user.

```
from abc import ABC, abstractmethod   
class Car(ABC):   
    def mileage(self):   
        pass  
  
class Tesla(Car):   
    def mileage(self):   
        print("The mileage is 30kmph")   
class Suzuki(Car):   
    def mileage(self):   
        print("The mileage is 25kmph ")   
class Duster(Car):   
    def mileage(self):   
          print("The mileage is 24kmph ")   
class Renault(Car):   
    def mileage(self):   
        print("The mileage is 27kmph ")   
```

- The class `Car` above is a generic class with no implementation of its functions, its essentially a skeleton class that gives out the structure of the class.

## Inheritance

Now lets talk about one of the most important concepts in OOP, inheriting different classes functionalities into your own class. There are a lot of different kinds of functionalities

**Simple Inheritance**: Simply inheriting a single class into your own.
Example:

```
class parent():
    def show():
        print("parent")
class child(parent):
    def showchild():
        print("child")
```

- This is a pretty straight forward example of inheritance, one class inheriting another class.

**Multilevel Inheritance:** You can layer inheritance as well, let me demonstrate:

```
class GrandParent():
    def show():
        print("This is the grandparent)
class Parent(GrandParent):
    def show():
        print("This is the parent")
class Child(Parent):
    def show():
        print("This is the child")
```

- See? you can chain inheritance as much as you want.

**Hierarchical Inheritance:** You can inherit a class multiple times:

```
class Dad():
    def show():
        print("this is dad")
class Son(Dad):
    def show():
        print("this is son")
class daughter(Dad):
    def show():
        print("this is daughter")
```

- Multiple children can inherit the same parent.

**Multiple Inheritance**: Kind of the opposite of Hierarchical Inheritance. Let me demonstrate:

```
class Dad():
    def show():
        print("this is dad")
class Mom():
    def show():
        print("This is mom")
class Child(Dad,Mom):
    def show():
        super().show()
        print("This is child")
```

- A child can inherit two classes, However you should be familiar with the `Method Resolution order` when you're working with this. The order is how you inherit the classes, here `class X(Y,Z)`, Y will take precedence over Z in the order.

## Static Variables

Python doesn't have a `static` keyword, but that doesn't mean we can't have static variables, the trick is to define the variable outside of any function, without using the `self` attribute, self is used to define instance variables.

```
class X():
    static_var=0
    def __init__(self):
        self.not_static_var=0
```

- Here, The `static_var` variable will behave just like a static variable in any other language.
- Static variables are the same for all objects, They belong to the class, if you change this variable in an object, the change will be reflected for all other objects.