Oop (c++)

·

10 min read

OOP Notes

  1. Encapsulation

  • Encapsulation in C++ is defined as the wrapping up of data and information in a single unit. In Object Oriented Programming, Encapsulation is defined as binding together the data and the functions that manipulate them.

  1. Abstraction

  • Abstraction means displaying only essential information and hiding the details. Data abstraction refers to providing only essential information about the data to the outside world, hiding the background details or implementation.

  • Hiding unnecessary information from users

  • Like the sort function in STL or built-in data structures

Why abstraction ?

  • Updating / changes

  • Avoid the error (if a prop is accessible to user so to protect it we use abstraction)

  1. Inheritance

  • The capability of a class to derive properties and characteristics from another class is called Inheritance. Inheritance is one of the most important features of Object-Oriented Programming.

  • Inheritance is a feature or a process in which new classes are created from the existing classes. The new class created is called “derived class” or “child class” and the existing class is known as the “base class” or “parent class”. The derived class now is said to be inherited from the base class.

  1. Access modifiers

  • Three access modifiers : Private , Public and Protected

  • A property declared as protected can only be accessed by its child class or inherited class

Hands on creating classes

  • Create a base class and derived class and access the protected property and also sets the value of a parameter of base class in the derived class

  •         #include <bits/stdc++.h>
            using namespace std;
            class Vechicle {
            private:
              int x;
    
            protected:
              int y;
    
            public:
              int z;
            };
            // how to inherit a class
            // class derived_class_name : access_specifier base_class_name
    
            class Car : public Vechicle {
            public:
              int gears;
    
            public:
              void print() { 
                cout << y << " " << z << " " << gears << endl; 
                }
    
                void setY(int val){
                    y = val;
                }
            };
            int main() {
              Car c;
              c.gears =  10;
            //   c.y = 20; // not accessible outside the class 
              c.z = 30;
              c.setY(10000);
              c.print();
            }
    

Order of constructor call

  • For B class we need the properties of A to be initialized so the constructor of A is called first, followed by the constructor of B.constructor of a will be called implicitly

  • As we know whenever an object is create it default constructor of its class ie being called internally

  • But we have explicitly call the parameterized constructor

Example

#include<iostream>
using namespace std ;
class Vehicle {
    private :
    int maxSpeed;
    protected:
    int numTyres;  
    public:
    std::string color;
    // deafult constructor
    Vehicle(){
        std::cout<<"Vechile's default constructor called"<<std::endl;
    }
    Vehicle(int n){
        cout<<"Vehicle parameterized constructor"<<endl;
        maxSpeed = n;
    }
    ~Vehicle(){
        std::cout<<"Vechile's default destructor called"<<std::endl;
    }
};
// we can also write 
// Car():Vehicle(){} (for calling the default constructor)
class Car : public Vehicle {
    public:
    int numGears;
    Car(int x , int y) :Vehicle(x){
        std::cout<<"Car's default constructor called"<<std::endl;
        numGears =  x;
    }
    ~Car(){
        std::cout<<"Car's default destructor called"<<std::endl;
    }
    void print(){
        std::cout<<"num tyres"<< numTyres<<std::endl;
        std::cout<<"color"<< color<<std::endl;
        std::cout<<"num gears"<< numGears<<std::endl;
    }
};
class HondaCity : public Car {
    public : 

    HondaCity(int x , int y) : Car(x , y){
        cout<<"Honda city's default constructor called"<<endl;
    }


    ~HondaCity(){
        cout<<"Honda city's default destructor called"<<endl;       
    }
};
 int main(){
    // Vehicle v;
    // Car c(6);
    HondaCity h(2 , 6);
 }

A class can only call the constructor of its parent class only

Types of Inheritance

  1. Basically four types of inheritance

  2. There is one more inheritance i.e. Hybrid Inheritance

Example of Mutiple Inheritance

#include<iostream>
// example of multiple constructor
using namespace std;
class Teacher{
    public:
    void print(){
        cout<<"hello ! this is teacher's print function"<<endl;
    }
};

class Student {
    public:
     void print(){
        cout<<"hello ! this is student's print function"<<endl;
    }
};


class TA:public Student  , public Teacher{
    public :
    TA(){
        cout<<"TA's class constructor"<<endl;
    }
};
int main(){
    TA t;
    t.Student::print();
}

-->First of all, it is clear that TA class in inheriting both the classes and in public mode so print function is also accessible outside the class or by the TA class

-->But there is one issue that is if we call print function then it will throw an error as both student class and teacher class contains print function

-->So to avoid this issue we will make use of scope resolution

Hybrid Inheritance (Virtual inheritance)

Example:

#include<iostream>
using namespace std ;
class Vehicle {
    private :
    int maxSpeed;
    protected:
    int numTyres;  
    public:
    std::string color;
    // deafult constructor
    Vehicle(){
        std::cout<<"Vechile's default constructor called"<<std::endl;
    }
};
// we can also write 
// Car():Vehicle(){} (for calling the default constructor)
class Car : public Vehicle {
    public:
    int numGears;
    Car(){
        std::cout<<"Car's default constructor called"<<std::endl;
    }
};
class Truck : public Vehicle {
    public : 

    Truck(){
        cout<<"Truck's default constructor called"<<endl;
    }
};


class Bus : public Car , public Truck{
    public :
    Bus(){
        cout<<"Bus default constructor's called"<<endl;
    }
};

 int main(){
    // Vehicle v;
    // Car c(6);
    Bus b;
 }

But a very serious issue is there that since bus inherit both car and truck class so it has multiple copies of Vehicle as well due to which it will throw us an error

we can use scope resolution to solve this problem

but still bus class has two copies of vehicle class

  1. Virtual keyword (to solve this ambiguity of multiple copies)

  2. ```cpp #include using namespace std ; class Vehicle { private : int maxSpeed; protected: int numTyres;
    public: std::string color; // deafult constructor // Vehicle(){ // std::cout<<"Vechile's default constructor called"<<std::endl; // }

    // let create parametrized constructor

    Vehicle(int z){ cout<<"parameterized constructor"<<" "<<z<<endl; }

    void print(){ cout<<"this is vehicle "<<endl; } }; // we can also write // Car():Vehicle(){} (for calling the default constructor) class Car : virtual public Vehicle { public: int numGears; Car():Vehicle(3){ std::cout<<"Car's default constructor called"<<std::endl; }

    void print(){ cout<<"this is car "<<endl; }

}; class Truck : virtual public Vehicle { public :

Truck():Vehicle(4){ cout<<"Truck's default constructor called"<<endl; } };

class Bus : public Car , public Truck{ public : Bus() :Vehicle(5){ cout<<"Bus default constructor's called"<<endl; }

void print(){ cout<<"this is bus "<<endl; } };

int main(){ // Vehicle v; // Car c(6); Bus b; //since bus class will call the constructor of vehicle class so 5 will get printed

// b.print(); // not give an error // b.Car::print(); // b.Truck::print();

// we can use virtual keyword to avoid mutiple copies of vechicle

}



**Very important thing to note in this that due to virtual class now neither car nor truck will call the Vehicle class constructor rather bus class will call the vehicle class constructor directly**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718803607015/a86f04a8-c2ac-4ab9-b226-31c88aa5fa1d.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718803639548/966b3b34-9c1d-4471-b9f2-699bdf80a296.png align="center")

we can say that actual objects are not present truck class has a pointer to vehicle class

# Polymorphism

Polymorphism means many forms

It is of two types

compile time

can be achieved by function overloading, operator overloading and function overriding

### *Function overloading*

functions with same name but diff structures

* but make sure structure should be same

* it will throw an error is name of function is same but return type is different

* ```cpp
                  #include<bits/stdc++.h>
                  using namespace std;

                  int test(int a  , int b){

                  }

                  int test(int a){

                  }

                  int test(){

                  }
                  // this is not allowed 
                  // can differentiate a fn with return type
                  // void test(){

                  // }
                  int main(){

                  }
  • Operator overloading

  • In this same operator will act differently

    • Function overriding

#include<bits/stdc++.h>
using namespace std;

 class Vehicle{
    public:
    string color;

    void print(){
        cout<<"Vehicle"<<endl;
    }
 };

class Car:Vehicle()  {
    public:
    int numGears;

    void print(){
        cout<<"Car"<<endl;
    }
};

int main(){

}
  • This is function overriding ie same function is base class as well as derived class

  •                 int main(){
                        Vehicle v;
                        Car c;
                        v.print();
                        c.print();
    
                    }
    
  • so at the compile time we are deciding whose function is to be called

  • so this is an example of compile time polymorphism

  • important thing to note is that we can point the pointer of parent class to the child class

  • v1->print () will print vehicle as it is straight forward

  • v1 is an object of vehicle class and pointing to v2 class

  • but v2 is pointing to car class but it itself an object of vehicle so no matter to whom it is pointing, it is an object of vehicle, and it will print vehicle class print function

  • through we can only access the properties of vehicle class only

  • But what if we want v2->print () should call car's print function (this decision we can take at run time)

  • to achieve that there is a concept of run time polymorphism

  • Run time polymorphism

  • So, we will make use of virtual function

  • virtual functions are those function which are present in base case and override in the derived class

  • we use virtual keyword (make the decision at run time)

  • in this we vehicle will be printed as we removed the print function of vehicle

  • but but but very important

  • if it was just opposite that is if vehicle's function was removed then in that case, it gives error as we know that through v2 we can access the properties of vehicle only

Pure Virtual Function

  •               virtual return_type function_name = 0 ;
                  // for example
                  virtual void print() = 0 ;
    
  • Any class contains any pure virtual function becomes abstract class

  • and we cannot create object of such class as function definition is missing

  • Now if any class in inheriting

#include<bits/stdc++.h>
using namespace std;

 class Vehicle{
    public:
    string color;

    virtual void print() = 0 ;
    // this is pure virtual function
 };

class Car:public Vehicle{
    public:
    int numGears;

    void print(){
        cout<<"Car"<<endl;
    }
};

int main(){ 
    Car c;
    c.print();
    // now vehicle class is abstract class  (print fn -> declration missing )
    // now option 1 : to complete function declaration 


}
  • Friend Function

  • Let's discuss again about access modifiers

  • we know that private properties are not accessible outside the class but

  • let say we want a function in other class to access the private property of some other class

  • with the help of friend function, we can achieve that

  • syntax of friend function

  •             //  
                friend return_type function/class //(we want to make friend of other class)
    
  • not only print () or function , we can create entire bus class to be friend of truck class

  • so in that case all member of bus class can access the private property of truck class

  • Let's create a TRUCK and BUS class first and make print() of bus class a friend of truck

  • Let say we have this :

  •             #include<bits/stdc++.h>
                using namespace std;
    
                class Truck {
                    private :
                    int x;
    
                    protected :
                    int y;
    
                    public:
                    int z ;
    
                };
    
                class Bus{
                    public :
                    void print (){
                        // we have to make this friend of truck class
                    }
                };
                int main(){
    
                }
    
  • Now let's make them friends

  • in this way we have to do it but there is a major issue with this code

  • ```cpp #include using namespace std;

    class Truck { private : int x;

    protected : int y;

    public: int z ;

    friend void Bus ::print();

};

class Bus{ public : void print (); // we are just declaring it , we provide it definiton outside };

void Bus::print(){ Truck t; t.x = 10; t.y = 20; cout<<t.x<<" "<<t.y<<endl; } int main(){

}


* **BUS::PRINT gives error as no class BUS exist above Truck so move the bus class upwards**

* ```cpp
              #include<bits/stdc++.h>
              using namespace std;
              class Bus{
                  public :
                  void print (); // we are just declaring it  , we provide it definiton outside
              };
              void Test();
              class Truck {
                  private :
                  int x;

                  protected :
                  int y;

                  public:
                  int z ;

                  friend void Bus ::print();
                  friend void Test();

              };
              void Bus::print(){
                  Truck t;
                  t.x = 10;
                  t.y = 20;
                  cout<<t.x<<" "<<t.y<<endl; 
              }
              void Test(){
                  Truck t;
                  t.x = 10;
                  t.y = 20;
                  cout<<t.x<<" "<<t.y<<endl; 
              }
              int main(){
                  Bus b;
                  b.print();
                  Test();
              }
  • vc

  • v

  • v