OOP Notes
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.
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)
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.
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
Basically four types of inheritance
-
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
Virtual keyword (to solve this ambiguity of multiple copies)
```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