Advance OOPS in C++ | A complete guide for Interviews

Advance OOPS in C++ | A complete guide for Interviews

💡 Four Pillars of Object-Oriented Programming:

  1. Encapsulation

  2. Inheritance

  3. Abstraction

  4. Polymorphism


// Human class
class Human {
private:
    string secret = "humansecret";

public:
    int age = 30, weight = 76;
};

// Student class
class Student : private Human {
public:
    string name = "student";
    void print() {
        cout << name << endl;
        cout << age << endl;
        cout << weight << endl;
    }
};

// GStudent class
class GStudent : public Student {
public:
    string name = "gstudent";
    void print() {
        cout << name << endl;
        cout << age << endl; // Inaccessible
        cout << weight << endl; // Inaccessible
    }
};

int main() {
    Student s1;
    // age, weight became private members of s1.
    cout << s1.age << endl; // Inaccessible
    cout << s1.weight << endl; // Inaccessible
    cout << s1.name << endl; // student
    s1.print(); // student 30 76

    GStudent g1;
    cout << g1.name << endl; // gstudent
    cout << g1.age << endl; // Inaccessible
    cout << g1.weight << endl; // Inaccessible

    return 0;
}

Encapsulation

To encapsulate something

The process of grouping data members and corresponding methods into a single unit is known as Encapsulation.

💡 We can create a fully encapsulated class by making all the data members private.

If the data members are private, they can only be accessed within the class; no other class can access that class’s data members.

Advantages of Encapsulation

  1. Encapsulation is a way to achieve data hiding because other classes will not be able to access the data through the private data members.

  2. It helps hide the data’s internal information, enhancing security.

  3. With encapsulation, you can make the class read-only.

  4. Encapsulation promotes code reusability.

  5. Encapsulated code is better for unit testing.

💡 Encapsulation also makes your code more testable, as you can isolate the unit of functionality that you want to test, and mock or stub the dependencies that you don't.

Summary: Data hiding, Security, Reusability of code, Testing.

Encapsulation in C++ - GeeksforGeeks

Inheritance [Most Important]

In C++, inheritance is a process in which one object automatically acquires all the properties and behaviors of its parent object. This allows you to reuse, extend, or modify the attributes and behaviors defined in other classes.

Advantages of Inheritance

  • The main advantage of inheritance is code reusability. We can reuse the code when we inherit the existing class’s methods and fields into a new class.

  • Runtime polymorphism (method overriding) can only be achieved through inheritance.

Modes of Inheritance

  1. Public mode: If a subclass is derived from a public base class, the base class’s public members become public in the derived class, and protected members remain protected.

  2. Protected mode: If a subclass is derived from a protected base class, both public and protected members of the base class become protected in the derived class.

  3. Private mode: If a subclass is derived from a private base class, both public and protected members of the base class become private in the derived class. Private members of the parent class are not inherited.

Base class visibility of members ⬇️PublicPrivateProtected
Private (no inheritance)Not InheritedNot InheritedNot Inherited
ProtectedProtectedPrivateProtected
PublicPublicPrivateProtected

💡 Private data members of the parent/super class can’t be inherited.

Types of Inheritance

C++ supports five types of inheritance:

  1. Single Inheritance
    In single inheritance, one class can extend the functionality of another class. There is only one parent class and one child class.

     class Animal {
     public:
         int age;
         int weight;
    
         void speak() {
             cout << "Speaking " << endl;
         }
     };
    
     class Dog: public Animal {
     };
    
  2. Multilevel Inheritance
    When a class inherits from a derived class, and the derived class becomes the base class of a new class, it is called multilevel inheritance.

     class Animal {
     public:
         void speak() {
             cout << "Speaking " << endl;
         }
     };
    
     class Dog: public Animal {
     };
    
     class GermanShepherd: public Dog {
     };
    
  3. Multiple Inheritance
    In multiple inheritance, a class can inherit more than one class. A single child class can have multiple parent classes.

     class Animal {
     public:
         void bark() {
             cout << "Barking " << endl;
         }
     };
    
     class Human {
     public:
         void speak() {
             cout << "Speaking " << endl;
         }
     };
    
     // Multiple Inheritance
     class HybridClassExample: public Animal, public Human {
     };
    
  4. Hierarchical Inheritance
    In hierarchical inheritance, one class serves as a base class for more than one derived class.

     class A {
     public:
         void func1() {
             cout << "Inside Function 1" << endl;
         }
     };
    
     class B: public A {
     public:
         void func2() {
             cout << "Inside Function 2" << endl;
         }
     };
    
     class C: public A {
     public:
         void func3() {
             cout << "Inside Function 3" << endl;
         }
     };
    
  5. Hybrid Inheritance
    Hybrid inheritance is a combination of more than one type of inheritance.

Ambiguity (The Diamond Problem)

Ambiguity arises when a class inherits member functions with the same name from two or more base classes, causing the compiler to be unsure which function to invoke.

Avoid Ambiguity Using Scope Resolution Operator

The ambiguity can be resolved by using the scope resolution operator to specify the class in which the member function lies:

object.class_name::method_name();

class A {
public:
    void func() {
        cout << " I am A" << endl;
    }
};

class B {
public:
    void func() {
        cout << " I am B" << endl;
    }
};

class C: public A, public B {
};

int main() {
    C obj;
    obj.A::func();
    obj.B::func();
    return 0;
}

Using the virtual keyword during inheritance avoids creating multiple copies of the same named variable/method.

Hybrid Inheritance in C++ with Diamond Problem and its Resolution | Virtual Inheritance in C++

Polymorphism [Very Important]

The term "Polymorphism" is derived from the Greek words "poly" + "morphs," meaning many forms.

For example, a woman behaves like a teacher in a classroom, a mother or daughter at home, and a customer in a market. A single person is behaving differently in various situations.

Compile-Time Polymorphism

  1. Function Overloading
    When there are multiple functions with the same name but different parameters, these functions are said to be overloaded.

     class Geeks {
     public:
         void func(int x) {
             cout << "value of x is " << x << endl;
         }
    
         void func(double x) {
             cout << "value of x is " << x << endl;
         }
    
         void func(int x, int y) {
             cout << "value of x and y is " << x << ", " << y << endl;
         }
     };
    
     int main() {
         Geeks obj1;
         obj1.func(7);
         obj1.func(9.132);
         obj1.func(85, 64);
         return 0;
     }
    
  2. Operator Overloading
    C++ allows overloading operators with special meanings for a data type.

     class Complex {
     private:
         int real, imag;
     public:
         Complex(int r = 0, int i = 0) {
             real = r;
             imag = i;
         }
    
         Complex operator+(Complex const& obj) {
             Complex res;
             res.real = real + obj.real;
             res.imag = imag + obj.imag;
             return res;
         }
    
         void print() { cout << real << " + i" << imag << endl; }
     };
    
     int main() {
         Complex c1(10, 5), c2(2, 4);
         Complex c3 = c1 + c2;
         c3.print(); // 12 + i9
         cout << 3 + 4<< endl; // 7 
     }
    

    Runtime Polymorphism

    (Method Overriding)
    A child class can provide its own version of an implementation without altering the original function.


class Animal {
public:
 void speak() {
     cout << "Speaking " << endl;
 }
};

class Dog: public Animal {
public:
 void speak() {
     cout << "Barking " << endl;
 }
};

int main() {
 Dog d;
 d.speak(); // Barking
}
class Animal {
public:
    void speak() {
        cout << "Speaking " << endl;
    }
};

class Dog: public Animal {
public:
    void speak() {
        cout << "Barking " << endl;
    }
};

int main() {
    Dog d;
    d.speak(); // Barking
}

Virtual functions, abstract classes (pure virtual functions), method overriding, compile-time vs. runtime polymorphism.

Abstract Class

An abstract class is a class that can’t be instantiated directly. These classes exist to serve as base classes for other derived classes. Abstract classes contain at least one pure virtual function.

💡 We cannot create an object of an abstract class.

class Animal {
public:
    virtual void sound() = 0; // Pure Virtual Function
};

class Dog: public Animal {
public:
    void sound() {
        cout << "Bark" << endl;
    }
};

Why Use Abstract Classes?

  1. Code Reusability: You can define common functionalities in the abstract class and extend them in derived classes.

  2. Runtime Polymorphism: Achieved using function overriding in derived classes.

Pure Virtual Functions and Abstract Classes

Friend Function

In C++, a friend function is a special function that can access the private and protected data members of a class.

💡 Friend functions are not members of the class but have the privilege to access private data.

class Box {
private:
    int length;
public:
    Box() : length(0) {}
    friend int printLength(Box);
};

int printLength(Box b) {
    b.length += 10;
    return b.length;
}

When to use friend functions:

  • If a function is not part of the class's functionality but needs to access its private or protected data.

  • To enable operator overloading when the left operand is not an object of the class.

class Box {
private:
    int length;
public:
    Box() : length(0) {}
    friend void setLength(Box&, int len);
    void displayLength() { cout << length << endl; }
};

void setLength(Box& b, int len) {
    b.length = len;
}

Destructor

A destructor is a special member function that is executed whenever an object of its class goes out of scope or is explicitly deleted.

class Person {
public:
    // Constructor
    Person() {
        cout << "Constructor is called." << endl;
    }

    // Destructor
    ~Person() {
        cout << "Destructor is called." << endl;
    }
};

int main() {
    Person p1;
    return 0;
}

The delete keyword is used to deallocate memory and calls the destructor.

Virtual Destructor

When we delete a derived class object using a base class pointer, the behavior is undefined if the destructor in the base class is not virtual.

class Base {
public:
    virtual ~Base() {
        cout << "Base class destructor called" << endl;
    }
};

class Derived : public Base {
public:
    ~Derived() {
        cout << "Derived class destructor called" << endl;
    }
};

int main() {
    Base *b = new Derived();
    delete b;
    return 0;
}

Abstraction Vs Encapsulation

Abstraction is generalized term. i.e. Encapsulation is subset of Abstraction.

AbstractionEncapsulation
It solves an issue at the design level.Encapsulation solves an issue at implementation level.
hides the unnecessary detail but shows the essential information.It hides the code and data into a single entity or unit so that the data can be protected from the outside world.
Focuses on the external lookout.Focuses on internal working.
Lets focus on what an object does instead of how it does it.Lets focus on how an object does something.
Example: Outer look of mobile, like it has a display screen and buttons.Example: Inner details of mobile, how button and display screen connect with each other using circuits.

https://stackoverflow.com/questions/742341/difference-between-abstraction-and-encapsulation