Object-Oriented Programming (OOP) is a programming paradigm that uses “objects” – data structures consisting of fields and methods – to design applications and programs. C++ is one of the most popular languages that supports OOP.
There are 4 pillars of OOP:
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
1️⃣ Encapsulation
Definition: Encapsulation is the practice of binding data and the methods that operate on that data into a single unit (class) and restricting direct access to some of the object’s components.
Why Encapsulation?
- It helps keep data safe from outside interference and misuse.
- Ensures better control over class data.
Key Concepts:
- Private members: Not accessible from outside the class.
- Public methods (getters/setters): Used to access and modify private members.
Example:
#include <iostream>
using namespace std;
class BankAccount {
private:
int balance; // Encapsulated (private)
public:
BankAccount() {
balance = 0;
}
void deposit(int amount) {
if (amount > 0)
balance += amount;
}
void withdraw(int amount) {
if (amount > 0 && balance >= amount)
balance -= amount;
}
int getBalance() {
return balance;
}
};
int main() {
BankAccount acc;
acc.deposit(500);
acc.withdraw(100);
cout << "Current Balance: " << acc.getBalance() << endl;
return 0;
}
Summary:
Encapsulation = Data hiding + Access control using public methods.
2️⃣ Abstraction
Definition: Abstraction means showing only the essential features of an object while hiding the unnecessary details.
Why Abstraction?
- It simplifies complex systems by breaking them into smaller, manageable parts.
- Focuses on what an object does instead of how it does it.
Key Concepts:
- Achieved through abstract classes and interfaces (pure virtual functions in C++).
- Pure virtual functions are defined using
= 0
.
Example:
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing Circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing Rectangle" << endl;
}
};
int main() {
Shape* s1 = new Circle();
Shape* s2 = new Rectangle();
s1->draw();
s2->draw();
delete s1;
delete s2;
return 0;
}
Summary:
Abstraction = Hiding implementation + Showing interface.
3️⃣ Inheritance
Definition: Inheritance allows a class (child or derived class) to inherit properties and behavior (methods) from another class (parent or base class).
Why Inheritance?
- Promotes code reusability.
- Establishes an “is-a” relationship.
Types of Inheritance in C++:
- Single
- Multiple
- Multilevel
- Hierarchical
- Hybrid
Example (Single Inheritance):
#include <iostream>
using namespace std;
class Animal {
public:
void eat() {
cout << "This animal eats food." << endl;
}
};
class Dog : public Animal {
public:
void bark() {
cout << "The dog barks." << endl;
}
};
int main() {
Dog myDog;
myDog.eat(); // Inherited
myDog.bark(); // Own function
return 0;
}
Example (Multiple Inheritance):
class A {
public:
void showA() {
cout << "Class A" << endl;
}
};
class B {
public:
void showB() {
cout << "Class B" << endl;
}
};
class C : public A, public B {
// Inherits both A and B
};
int main() {
C obj;
obj.showA();
obj.showB();
return 0;
}
Summary:
Inheritance = Reuse existing code + Establish relationships between classes.
4️⃣ Polymorphism
Definition: Polymorphism allows functions or methods to behave differently based on the object or data they are operating on. Literally, it means “many forms”.
Why Polymorphism?
- Increases flexibility and scalability.
- Reduces code duplication.
Types of Polymorphism:
- Compile-time (Static) Polymorphism
- Function Overloading
- Operator Overloading
- Run-time (Dynamic) Polymorphism
- Function Overriding using virtual functions
Compile-time Polymorphism
Function Overloading:
class Print {
public:
void show(int i) {
cout << "Integer: " << i << endl;
}
void show(string s) {
cout << "String: " << s << endl;
}
};
int main() {
Print obj;
obj.show(100);
obj.show("Hello");
return 0;
}
Operator Overloading:
class Complex {
private:
int real, imag;
public:
Complex(int r, int i) : real(r), imag(i) {}
Complex operator + (const Complex& obj) {
return Complex(real + obj.real, imag + obj.imag);
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2;
c3.display();
return 0;
}
Run-time Polymorphism
Function Overriding with Virtual Functions:
class Animal {
public:
virtual void sound() {
cout << "Some generic animal sound" << endl;
}
};
class Cat : public Animal {
public:
void sound() override {
cout << "Meow" << endl;
}
};
int main() {
Animal* a = new Cat();
a->sound(); // Calls Cat's version due to virtual function
delete a;
return 0;
}
Summary:
Polymorphism = One interface, many implementations.
The Diamond Problem in C++
What is the Diamond Problem?
The Diamond Problem is a classic ambiguity issue in multiple inheritance, where a derived class inherits from two classes that have a common base class.
Structure of the Diamond:
A
/ \
B C
\ /
D
- Class
B
and classC
inherit from classA
. - Class
D
inherits from bothB
andC
.
The Problem:
When class D
tries to access a member of class A
, C++ compiler doesn’t know whether to use the A
part of B
or the A
part of C
, because both contain their own copies of A
.
Example of the Diamond Problem
#include <iostream>
using namespace std;
class A {
public:
void display() {
cout << "Class A" << endl;
}
};
class B : public A { };
class C : public A { };
class D : public B, public C { };
int main() {
D obj;
// obj.display(); // Error: Ambiguous!
obj.B::display(); // Okay: Access through B's A
obj.C::display(); // Okay: Access through C's A
return 0;
}
Explanation:
- Class
D
has two copies of classA
(one fromB
, one fromC
). - If you call
obj.display()
, the compiler gets confused — whichdisplay()
function to call? - This is the Diamond Problem.
Solution: Virtual Inheritance
C++ allows us to solve this using virtual inheritance. This tells the compiler to share a single copy of the base class when it appears multiple times in an inheritance hierarchy.
Modified Example Using Virtual Inheritance:
#include <iostream>
using namespace std;
class A {
public:
void display() {
cout << "Class A (via virtual inheritance)" << endl;
}
};
class B : virtual public A { };
class C : virtual public A { };
class D : public B, public C { };
int main() {
D obj;
obj.display(); // No ambiguity now
return 0;
}
What Changed:
- We added
virtual
beforepublic A
inB
andC
. - Now, class
D
contains only one shared instance of classA
. - No ambiguity – problem solved!
Virtual Functions vs Virtual Inheritance
These terms may sound similar, but they solve different problems:
Concept | Purpose | Usage Context |
---|---|---|
Virtual Functions | Enable dynamic (runtime) polymorphism | Function overriding |
Virtual Inheritance | Avoid multiple copies of a base class (diamond problem) | Multiple inheritance |
Virtual Functions Recap
Virtual functions ensure the correct function is called for an object, regardless of the reference type, when using base class pointers or references.
Example:
class Animal {
public:
virtual void sound() {
cout << "Generic animal sound" << endl;
}
};
class Dog : public Animal {
public:
void sound() override {
cout << "Bark" << endl;
}
};
int main() {
Animal* a = new Dog();
a->sound(); // Calls Dog's sound(), not Animal's
delete a;
return 0;
}
Why use virtual
?
Without it, a->sound()
would call Animal
’s version instead of Dog
’s.
Summary
- The Diamond Problem happens due to ambiguous inheritance paths in multiple inheritance.
- Use virtual inheritance to ensure only one instance of the base class exists.
- Virtual functions provide runtime polymorphism, letting you override functions dynamically.
- Both features are powerful tools in C++, each solving a different class of problem.
Final Thoughts
Pillar | Purpose | Achieved via |
---|---|---|
Encapsulation | Hide data, protect from misuse | Access specifiers + Getters/Setters |
Abstraction | Show essential, hide details | Abstract classes, interfaces |
Inheritance | Reuse code | Derived classes from base classes |
Polymorphism | One name, many forms | Overloading, Overriding, Virtual func |
Programming Tasks
- Encapsulation Task:
Write a classStudent
with private members:name
,rollNumber
, andGPA
. Add public methods to set and get each of these values. Include validation for GPA (should be between 0.0 and 4.0). - Abstract Shape Class:
Create an abstract classShape
with a pure virtual functionarea()
. Derive classesRectangle
andCircle
from it, and override thearea()
function appropriately. Test the behavior using base class pointers. - Polymorphism via Virtual Functions:
Design a classEmployee
with a virtual functiongetSalary()
. Derive classesManager
andEngineer
from it, each returning different salary values. Demonstrate runtime polymorphism using base class pointers. - Diamond Problem Handling:
Implement a class hierarchy that causes the diamond problem, and then resolve it using virtual inheritance. Demonstrate that there is only one instance of the base class in the final derived class.
Thanks for the recommendations you have provided here. Another thing I would like to mention is that computer system memory needs generally rise along with other innovations in the technology. For instance, whenever new generations of processor chips are made in the market, there is usually a matching increase in the type demands of all laptop or computer memory in addition to hard drive room. This is because the program operated by simply these processor chips will inevitably rise in power to use the new technological innovation.
Thank you for writing this post. I like the subject too. http://www.kayswell.com
Whats up are using WordPress for your blog platform? I’m new to the blog world but I’m trying to get started and create my own. Do you need any html coding knowledge to make your own blog? Any help would be greatly appreciated!
I use WordPress and you can get started without knowing any HTML