Inheritance — From Zero
What is Inheritance?
Inheritance is an OOP mechanism where a new class (derived/child) acquires properties and behaviors from an existing class (base/parent). The core idea: reuse + extend.
Syntax
#include <iostream>
using namespace std;
class Base {
public:
int x;
void show() { cout << "Base show: " << x << "\n"; }
};
class Derived : public Base { // colon = "inherits from"
public:
int y;
void display() { cout << "Derived display: " << y << "\n"; }
};
int main() {
Derived d;
d.x = 10;
d.y = 20;
d.show();
d.display();
return 0;
}
Base show: 10
Derived display: 20
Types of Inheritance
| Type | Syntax | Meaning |
|---|---|---|
| Single | class B : public A | One derived from one base |
| Multiple | class C : public A, public B | One derived from many bases |
| Multilevel | A → B → C | Chain of inheritance |
| Hierarchical | A → B, A → C | Many derived from one base |
| Hybrid | Mix of above | Combination (can cause diamond problem) |
Single Inheritance — Full Example
#include <iostream>
#include <string>
using namespace std;
// Base class
class Animal {
public:
string name;
void eat() { cout << name << " is eating\n"; }
};
// Derived class inherits Animal
class Dog : public Animal {
public:
void bark() { cout << name << " says Woof!\n"; }
};
int main() {
Dog d;
d.name = "Rex"; // inherited from Animal
d.eat(); // inherited method
d.bark(); // own method
return 0;
}
Rex is eating
Rex says Woof!
Multiple Inheritance
#include <iostream>
using namespace std;
class Father { public: void wealth() { cout << "Rich\n"; } };
class Mother { public: void talent() { cout << "Creative\n"; } };
class Child : public Father, public Mother {
public:
void intro() { wealth(); talent(); }
};
int main() {
Child c;
c.intro();
return 0;
}
Rich
Creative
virtual inheritance:
class B : virtual public AMultilevel Inheritance
#include <iostream>
using namespace std;
class Grandparent { public: void gp() { cout << "GP\n"; } };
class Parent : public Grandparent { public: void p() { cout << "P\n"; } };
class Child : public Parent { public: void c() { cout << "C\n"; } };
int main() {
Child ch;
// Child has access to gp(), p(), and c()
ch.gp();
ch.p();
ch.c();
return 0;
}
GP
P
C
class A { public: int x; };
class B : public A { public: int y; }; // Single
class C : public B { public: int z; }; // Multilevel
class Base {}; class Derived : public Base {};
Access Specifiers in Inheritance
Member Access in Classes
| Specifier | Same Class | Derived Class | Outside World |
|---|---|---|---|
public |
✓ | ✓ | ✓ |
protected |
✓ | ✓ | ✗ |
private |
✓ | ✗ | ✗ |
Inheritance Mode Effect
How members are inherited depends on the inheritance mode used in the derived class:
| Base Member | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | Not inherited | Not inherited | Not inherited |
Code Example
#include <iostream>
using namespace std;
class Base {
public: int pub = 1;
protected: int prot = 2;
private: int priv = 3;
};
class D1 : public Base {
public:
void test() {
pub = 10; // OK — still public
prot = 20; // OK — still protected
// priv = 30; ERROR — not accessible
cout << "D1 test: pub=" << pub << " prot=" << prot << "\n";
}
};
class D2 : private Base {
public:
void test() {
pub = 10; // OK — but now private in D2
prot = 20; // OK — but now private in D2
cout << "D2 test: pub=" << pub << " prot=" << prot << "\n";
}
};
int main() {
D1 d1;
d1.pub = 5; // OK — public inheritance keeps it public
d1.test();
D2 d2;
// d2.pub = 5; ERROR — private inheritance makes it private
d2.test();
return 0;
}
D1 test: pub=10 prot=20
D2 test: pub=10 prot=20
class Base { private: int a; protected: int b; public: int c; };
class Derived : public Base { void test(){ b=1; c=2; /* a=3; ERROR */ } };
Constructor & Destructor Order
The Golden Rule
Order of Execution
Construction: Base constructor → Derived constructor
Destruction: Derived destructor → Base destructor
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base Constructor\n"; }
~Base() { cout << "Base Destructor\n"; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived Constructor\n"; }
~Derived() { cout << "Derived Destructor\n"; }
};
int main() {
cout << "--- Creating d ---\n";
{
Derived d;
cout << "--- d goes out of scope ---\n";
}
return 0;
}
--- Creating d ---
Base Constructor
Derived Constructor
--- d goes out of scope ---
Derived Destructor
Base Destructor
Passing Arguments to Base Constructor
Use initializer list syntax to pass arguments to base class constructor:
#include <iostream>
using namespace std;
class Base {
int x;
public:
Base(int a) : x(a) { cout << "Base(" << x << ")\n"; }
};
class Derived : public Base {
int y;
public:
Derived(int a, int b) : Base(a), y(b) { // Base(a) called first
cout << "Derived(" << y << ")\n";
}
};
int main() {
Derived d(10, 20);
return 0;
}
Base(10)
Derived(20)
Multiple Inheritance Constructor Order
#include <iostream>
using namespace std;
class A { public: A() { cout << "A\n"; } };
class B { public: B() { cout << "B\n"; } };
class C : public A, public B {
public:
C() { cout << "C\n"; }
};
int main() {
C c;
return 0;
}
A
B
C
class C : public A, public B), NOT the order in the
initializer list!class Base { public: Base(){ cout<<"B"; } };
class Derived : public Base { public: Derived(){ cout<<"D"; } };
int main(){ Derived obj; }
BDFriend Functions & Inline Functions
Friend Functions
Key Facts
• Declared inside class with friend keyword, defined outside
• NOT a member function — called without object
• Has access to private & protected members
• Can be friend of multiple classes
• NOT inherited by derived classes
#include <iostream>
using namespace std;
class Box {
int length; // private
public:
Box(int l) : length(l) {}
friend void printLength(Box b); // friend declaration
};
void printLength(Box b) {
cout << "Length: " << b.length << "\n"; // accessing private!
}
int main() {
Box b(10);
printLength(b); // called without object
return 0;
}
Length: 10
Friend Class
#include <iostream>
using namespace std;
class Engine; // forward declaration
class Car {
int speed = 200;
public:
friend class Engine; // Engine can access Car's privates
};
class Engine {
public:
void tune(Car& c) {
cout << "Speed: " << c.speed << "\n"; // OK — Engine is friend of Car
}
};
int main() {
Car myCar;
Engine myEngine;
myEngine.tune(myCar);
return 0;
}
Speed: 200
Inline Functions
The inline keyword requests the compiler to replace a function call with the actual function
code — eliminating call overhead.
#include <iostream>
using namespace std;
inline int square(int x) { return x * x; }
int main() {
cout << square(5) << "\n"; // compiler replaces with: cout << 5*5;
return 0;
}
25
| Inline | Normal Function |
|---|---|
| No call overhead | Stack frame created |
| Code duplicated at each call | One copy in memory |
| Best for small, frequent functions | Best for large functions |
Compiler may ignore inline |
Always respected |
class Box { int width; friend void setWidth(Box &b, int w); };
void setWidth(Box &b, int w){ b.width = w; }
Virtual Functions & Runtime Polymorphism
The Problem Without virtual
#include <iostream>
using namespace std;
class Animal {
public:
void speak() { cout << "Animal speaks\n"; }
};
class Dog : public Animal {
public:
void speak() { cout << "Dog barks\n"; }
};
int main() {
Animal* ptr = new Dog();
ptr->speak(); // Output: "Animal speaks" ← WRONG!
// Without virtual, base class version always called via pointer
delete ptr;
return 0;
}
Animal speaks
Solution: virtual Keyword
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() { cout << "Animal speaks\n"; }
};
class Dog : public Animal {
public:
void speak() override { cout << "Dog barks\n"; }
};
class Cat : public Animal {
public:
void speak() override { cout << "Cat meows\n"; }
};
int main() {
Animal* p1 = new Dog();
Animal* p2 = new Cat();
p1->speak(); // Dog barks ✓
p2->speak(); // Cat meows ✓
// Decision made at RUNTIME — Runtime Polymorphism
delete p1;
delete p2;
return 0;
}
Dog barks
Cat meows
How it Works — VTable (Internal Mechanics)
Virtual Table (VTable)
Every class with virtual functions has a hidden VTable — a table of function
pointers.
Every object has a hidden vptr — a pointer to its class's VTable.
When you call ptr->speak(), the runtime looks up the VTable via vptr and calls the
correct function.
Memory Layout:
Animal object: [ vptr → Animal::VTable [ speak → Animal::speak ] ]
Dog object: [ vptr → Dog::VTable [ speak → Dog::speak ] ]
So ptr-speak() goes: ptr → vptr → VTable → correct function
virtual Destructor — CRITICAL
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() { cout << "Base destroyed\n"; }
};
class Derived : public Base {
public:
~Derived() { cout << "Derived destroyed\n"; }
};
int main() {
Base* p = new Derived();
delete p;
// Without virtual destructor: only Base destroyed → MEMORY LEAK
// With virtual destructor: Derived destroyed, then Base ✓
return 0;
}
Derived destroyed
Base destroyed
Function Overriding vs Overloading
| Feature | Overloading | Overriding |
|---|---|---|
| Where | Same class | Base & Derived class |
| Signature | Different | Same |
| When resolved | Compile time | Runtime (with virtual) |
| Keyword | None needed | virtual + override |
class Base { public: virtual void show(){ cout<<"B"; } };
class Derived : public Base { public: void show(){ cout<<"D"; } };
int main(){ Base *p; Derived d; p=&d; p->show(); }
DPure Virtual Functions & Abstract Classes
Pure Virtual Function
A pure virtual function has no body — it FORCES derived classes to implement it:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() = 0; // "= 0" makes it pure virtual
};
class Dog : public Animal {
public:
void speak() override { cout << "Woof\n"; }
};
int main() {
Dog d;
d.speak();
return 0;
}
Woof
Abstract Class Rules
Rules you MUST know
• A class with at least ONE pure virtual function = Abstract class
• Abstract class CANNOT be instantiated (no objects)
• Derived class MUST override ALL pure virtual functions
• If derived class doesn't override all → it also becomes abstract
• Abstract class CAN have constructors (called when derived is created)
• Abstract class CAN have non-pure (regular) virtual functions
#include <iostream>
using namespace std;
class Shape { // Abstract class
public:
virtual double area() = 0; // pure virtual
virtual double perimeter() = 0; // pure virtual
virtual void draw() { cout << "Drawing shape\n"; } // regular virtual
};
class Circle : public Shape {
double r;
public:
Circle(double r) : r(r) {}
double area() override { return 3.14 * r * r; }
double perimeter() override { return 2 * 3.14 * r; }
};
class Rectangle : public Shape {
double w, h;
public:
Rectangle(double w, double h) : w(w), h(h) {}
double area() override { return w * h; }
double perimeter() override { return 2 * (w + h); }
};
int main() {
// Shape s; ← ERROR: cannot instantiate abstract class
Shape* shapes[] = { new Circle(5), new Rectangle(4,6) };
for (auto s : shapes) {
cout << "Area: " << s->area() << "\n";
}
for (auto s : shapes) delete s; // Cleanup
return 0;
}
Area: 78.5
Area: 24
Interface in C++ (100% Abstract)
C++ doesn't have the interface keyword like Java, but you can simulate it — a class with ALL
pure virtual functions acts as an interface:
#include <iostream>
using namespace std;
class IPrintable { // "Interface"
public:
virtual void print() = 0;
virtual void save() = 0;
virtual ~IPrintable() = default;
};
class Document : public IPrintable {
public:
void print() override { cout << "Printing Document\n"; }
void save() override { cout << "Saving Document\n"; }
};
int main() {
Document doc;
doc.print();
doc.save();
return 0;
}
Printing Document
Saving Document
class Shape { public: virtual void draw()=0; };
class Circle : public Shape { public: void draw(){ cout<<"Draw"; } };
UML Class Diagrams
UML Box Structure
A class in UML has 3 compartments
+------------------+
| ClassName | ← Class Name (bold)
+------------------+
| - privateAttr | ← Attributes
| # protectedAttr |
| + publicAttr |
+------------------+
| + publicMethod() | ← Methods
| - privateMethod()|
+------------------+
Visibility symbols: + public - private
# protected
Relationships in UML
| Relationship | Symbol | Meaning | C++ Code |
|---|---|---|---|
| Inheritance | → (solid line, hollow arrow) | "is-a" | class Dog : Animal |
| Association | — (solid line) | "uses-a" | pointer/ref member |
| Aggregation | ◇— (hollow diamond) | "has-a" (weak) | object passed in |
| Composition | ◆— (filled diamond) | "part-of" (strong) | object member |
| Dependency | --→ (dashed arrow) | "depends-on" | used in method |
Reading a UML Diagram — Example
+----------+
| Animal | ← Abstract (italic name)
+----------+
| # name |
+----------+
| + speak()*| ← * = pure virtual
+----------+
△ ← Inheritance arrow
_______|_______
| |
+---------+ +---------+
| Dog | | Cat |
+---------+ +---------+
| +speak()| | +speak()|
+---------+ +---------+
Exam Questions & Quick Quiz
2-Mark Questions
Q1. What is inheritance? Name its types.
Q2. What is a virtual function?
virtual keyword in base class, overridden in
derived. Enables runtime polymorphism — correct version selected based on actual object type at
runtime via VTable.Q3. What is a pure virtual function?
Q4. What is the order of constructor/destructor calls in inheritance?
Q5. Difference between function overloading and overriding?
5-Mark Questions
Q6. Explain access specifiers with table and example.
Q7. Write a program demonstrating runtime polymorphism using virtual functions.
Q8. What is an abstract class? How is it different from a concrete class?
MCQ Rapid Fire
Which symbol is used for inheritance in UML?
Can you create object of abstract class?
What happens if derived class doesn't override all pure virtual functions?
Friend function is a member of the class — True or False?
What is diamond problem? How is it solved?
class B : virtual public A.
Revision Sheet — 1-Minute Recall
Unit 3 Key Points
✦ Inheritance: reuse + extend. 5 types: S,M,ML,H,Hybrid
✦ Access: public=everywhere, protected=family, private=self only
✦ Constructor order: Base→Derived. Destructor: Derived→Base
✦ Friend: not a member, has private access, not inherited
✦ Inline: code pasted at call site, no overhead, good for small functions
✦ Virtual: = 0 means pure, class abstract, VTable used at runtime
✦ Abstract class: can't instantiate, blueprint, forces implementation
✦ UML: + public, - private, # protected. △ = inheritance arrow
Practice — Inheritance
Show Solution ▾
class Vehicle {
public:
string brand; int speed;
Vehicle(string b, int s) : brand(b), speed(s) {}
virtual void describe() {
cout << "Brand:" << brand << " Speed:" << speed << "\n";
}
};
class Car : public Vehicle {
public:
string fuelType;
Car(string b, int s, string f): Vehicle(b,s), fuelType(f) {}
void describe() override {
Vehicle::describe();
cout << "Fuel:" << fuelType << "\n";
}
};
class ElectricCar : public Car {
public:
int batteryRange;
ElectricCar(string b, int s, int r)
: Car(b,s,"Electric"), batteryRange(r) {}
void describe() override {
Car::describe();
cout << "Range:" << batteryRange << "km\n";
}
};Show Solution ▾
class Flyable {
public:
virtual void fly() { cout << "Flying!\n"; }
};
class Swimmable {
public:
virtual void swim() { cout << "Swimming!\n"; }
};
class Duck : public Flyable, public Swimmable {
public:
void fly() override { cout << "Duck flies low!\n"; }
void swim() override { cout << "Duck paddles!\n"; }
void action() { fly(); swim(); }
};Show Solution ▾
class Shape {
public:
virtual double getArea() = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
double r;
public:
Circle(double r):r(r){}
double getArea() override { return 3.14*r*r; }
};
class Rectangle : public Shape {
double w,h;
public:
Rectangle(double w,double h):w(w),h(h){}
double getArea() override { return w*h; }
};
int main() {
Shape* shapes[] = {new Circle(5), new Rectangle(4,6)};
if(auto s:shapes) cout << s->getArea() << "\n";
}public
inheritance for "is-a". Private = "implemented-in-terms-of". Protected = rarely used.Derived(args) : Base(base_args) {}Predict Output — Constructor & Virtual Dispatch
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A()\n"; }
~A() { cout << "~A()\n"; }
};
class B : public A {
public:
B() { cout << "B()\n"; }
~B() { cout << "~B()\n"; }
};
class C : public B {
public:
C() { cout << "C()\n"; }
~C() { cout << "~C()\n"; }
};
int main() {
C obj;
return 0;
}
Reveal Answer ▾
Output:A()B()C()~C()~B()~A()Constructors: Base→Derived (A→B→C). Destructors: reverse (C→B→A).
#include <iostream>
using namespace std;
class Animal {
public:
void speak() { cout << "Animal\n"; }
virtual void move() { cout << "Animal moves\n"; }
};
class Dog : public Animal {
public:
void speak() { cout << "Dog\n"; }
void move() override { cout << "Dog runs\n"; }
};
int main() {
Animal* p = new Dog();
p->speak();
p->move();
delete p;
return 0;
}
Reveal Answer ▾
Output:AnimalDog runsExplanation: speak() is NOT virtual → resolved at compile time via pointer type (Animal*) → prints "Animal". move() IS virtual → resolved at runtime via VTable based on actual object type (Dog) → prints "Dog runs". This is the most common exam trap!
#include <iostream>
using namespace std;
class X { public: X() { cout << "X "; } };
class Y { public: Y() { cout << "Y "; } };
class Z : public Y, public X {
public:
Z() : X(), Y() { cout << "Z"; }
};
int main() {
Z z;
return 0;
}
Reveal Answer ▾
Output:Y X ZTRAP: The initializer list order
: X(), Y() is IGNORED! Constructors are called in the
order of inheritance declaration: class Z : public Y, public X → Y first, then
X.#include <iostream>
using namespace std;
class Base {
public:
~Base() { cout << "~Base\n"; } // NOT virtual!
};
class Derived : public Base {
public:
~Derived() { cout << "~Derived\n"; }
};
int main() {
Base* p = new Derived();
delete p;
return 0;
}
Reveal Answer ▾
Output:~Base ← ONLY
base destructor called!Problem: ~Derived() is NEVER called → memory leak if Derived has dynamically allocated resources. Fix: make Base destructor virtual:
virtual ~Base(). Then output would be:
~Derived → ~Base (correct order).Debug This — Find & Fix the Bugs
#include <iostream>
using namespace std;
class Shape {
public:
virtual double area() = 0;
};
class Circle : public Shape {
double r;
public:
Circle(double r) : r(r) {}
// forgot to override area()
};
int main() {
Shape s; // line A
Circle c(5); // line B
cout << c.area(); // line C
return 0;
}
Show Fix ▾
Errors:• Line A: Cannot instantiate abstract class Shape (has pure virtual area())
• Line B & C: Circle didn't override area() → Circle is also abstract → cannot instantiate
Fix: Remove line A. Add to Circle:
double area() override { return 3.14 * r * r; }
#include <iostream>
using namespace std;
class Base {
private:
int x = 10;
public:
int getX() { return x; }
};
class Derived : public Base {
public:
void show() {
cout << x; // line A
cout << getX(); // line B
}
};
int main() {
Derived d;
d.show();
return 0;
}
Show Fix ▾
Error: Line A —x is
private in Base. Cannot access private member from derived class, even with public
inheritance.Fix: Line A is wrong. Line B is correct — use the public getter
getX().If direct access needed: change
private: to protected: in Base.
#include <iostream>
using namespace std;
class A { public: void hello() { cout << "A\n"; } };
class B : public A {};
class C : public A {};
class D : public B, public C {};
int main() {
D d;
d.hello(); // ERROR!
return 0;
}
Show Fix ▾
Error: Ambiguous — D has TWO copies of A (one via B, one via C). Compiler doesn't know which hello() to call: B::A::hello() or C::A::hello()?Fix Option 1 — Explicit scope:
d.B::hello(); or d.C::hello();Fix Option 2 — Virtual inheritance (proper fix):
class B : virtual public A {};class C : virtual public A {};Now D has only ONE copy of A.
d.hello() works without ambiguity.
#include <iostream>
using namespace std;
class Animal {
public:
int* data;
Animal() { data = new int[100]; }
~Animal() { delete[] data; cout << "Animal cleaned\n"; }
};
class Dog : public Animal {
public:
int* extra;
Dog() { extra = new int[50]; }
~Dog() { delete[] extra; cout << "Dog cleaned\n"; }
};
int main() {
Animal* p = new Dog();
delete p; // MEMORY LEAK!
return 0;
}
Show Fix ▾
Problem: ~Animal() is not virtual. Whendelete p called via Animal pointer, only Animal's destructor runs.
Dog's destructor is NEVER called → extra array leaks (50 ints = 200 bytes
lost).Fix: Add
virtual to Animal's
destructor:virtual ~Animal() { delete[] data; }Now delete p → calls ~Dog() first → then ~Animal() → no leak.
Edge Cases & Tricky Scenarios
1. Calling Virtual Function from Constructor
#include <iostream>
using namespace std;
class Base {
public:
Base() { speak(); } // calling virtual from constructor!
virtual void speak() { cout << "Base speak\n"; }
};
class Derived : public Base {
public:
void speak() override { cout << "Derived speak\n"; }
};
int main() {
Derived d;
return 0;
}
// Output: "Base speak" ← NOT "Derived speak"!
2. Slicing Problem
#include <iostream>
using namespace std;
class Animal { public: virtual void speak() { cout << "Animal\n"; } };
class Dog : public Animal { public: void speak() override { cout << "Dog\n"; } };
int main() {
Animal a = Dog(); // OBJECT slicing — Dog part is cut off!
a.speak(); // Prints "Animal" — Dog's speak() is LOST
Animal* p = new Dog(); // pointer — NO slicing
p->speak(); // Prints "Dog" — correct!
delete p;
return 0;
}
3. Pure Virtual with Body
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() = 0; // pure virtual CAN have a body!
};
void Base::show() { cout << "Base impl\n"; } // defined outside
class Derived : public Base {
public:
void show() override {
Base::show(); // explicitly call base version
cout << "Derived\n";
}
};
int main() {
Derived d;
d.show();
return 0;
}
A pure virtual function CAN have a body — but class is still abstract. Derived must still override it. The body can only be called via explicit scope resolution.
4. Overriding vs Hiding
#include <iostream>
using namespace std;
class Base {
public:
virtual void show(int x) { cout << "Base: " << x; }
};
class Derived : public Base {
public:
void show() { cout << "Derived"; } // DIFFERENT signature!
// This HIDES Base::show(int), NOT overrides it!
};
int main() {
Derived d;
// d.show(5); ERROR — Base::show(int) is hidden!
d.Base::show(5); // Only way to call it
return 0;
}
override keyword to let compiler catch this mistake!UML Practice — Draw & Interpret
📐 Step-by-Step: How to Draw UML from Code
List every class. Each becomes a UML box with 3 sections: name | attributes | methods.
public → +, private → -, protected →
#. Write type after colon: + name : string
Inheritance = hollow triangle arrow (→) pointing TO base. Composition = filled diamond (◆). Association = plain line.
Abstract class name and pure virtual methods in italics or with {abstract} label.
class Person {
protected: string name; int age;
public:
virtual void display() = 0;
string getName();
};
class Student : public Person {
private: int rollNo;
public:
void display() override;
float getGPA();
};
class Teacher : public Person {
private: string subject;
public:
void display() override;
void teach();
};
Show UML ▾
#includeusing namespace std; +====================+ | <<abstract>> | | Person | ← abstract (italics in real UML) +====================+ | # name : string | | # age : int | +--------------------+ | + display() * | ← * = pure virtual | + getName() : str | +====================+ △ (hollow triangle = inheritance) _________|__________ | | +==================+ +==================+ | Student | | Teacher | +==================+ +==================+ | - rollNo : int | | - subject : str | +------------------+ +------------------+ | + display() | | + display() | | + getGPA():float | | + teach() | +==================+ +==================+
• Abstract class
Appliance: protected watts(int), pure virtual powerOn()•
WashingMachine inherits Appliance: private capacity(int), overrides powerOn(), adds
wash()•
Refrigerator inherits Appliance: private temperature(float), overrides powerOn(),
adds cool()Show Code ▾
class Appliance {
protected: int watts;
public:
Appliance(int w):watts(w){}
virtual void powerOn() = 0;
virtual ~Appliance(){}
};
class WashingMachine : public Appliance {
int capacity;
public:
WashingMachine(int w,int c):Appliance(w),capacity(c){}
void powerOn() override { cout<<"WM ON\n"; }
void wash() { cout<<"Washing\n"; }
};
class Refrigerator : public Appliance {
float temperature;
public:
Refrigerator(int w,float t):Appliance(w),temperature(t){}
void powerOn() override { cout<<"Fridge ON\n"; }
void cool() { cout<<"Cooling\n"; }
};Active Recall — Test Yourself Without Notes
1. Write the exact syntax to inherit B from A using public mode.
class B : public A { };2. What does = 0 after a function declaration mean?
3. Can an abstract class have a constructor?
4. A class has 3 pure virtual functions. Derived overrides only 2. What happens?
5. What is VTable? What contains it?
6. What is the difference between overriding and hiding?
7. Why must destructor be virtual in polymorphism?
8. Friend function — is it inherited? Can it access private members?
9. What is inline function? When does the compiler ignore inline?
10. Write the UML visibility symbols for public, private, protected.
11. In multiple inheritance class C : public A, public B — which constructor is called first?
12. What is the diamond problem? One sentence.
Final Exam Coding Programs
12 full exam-level programs. Attempt without looking at solution first.
Show Solution ▾
#include
using namespace std;
class Account {
protected: double balance; int accountNo;
public:
Account(int no, double bal): accountNo(no), balance(bal){}
virtual double calculateInterest() = 0;
virtual void display() = 0;
virtual ~Account(){}
};
class SavingsAccount : public Account {
double rate;
public:
SavingsAccount(int no, double bal, double r): Account(no,bal), rate(r){}
double calculateInterest() override { return balance*rate/100; }
void display() override { cout "Savings Acc#" " Interest:" calculateInterest() "\n"; }
};
int main() {
Account* a = new SavingsAccount(101, 10000, 4.5);
a-display();
delete a;
return 0;
}
Show Solution ▾
#include
using namespace std;
class Employee {
protected: string name; int id;
public:
Employee(string n,int i):name(n),id(i){}
virtual double calculateSalary()=0;
virtual void display(){cout<<name<<" Salary:"<<calculateSalary()<<"\n";}
virtual ~Employee(){}
};
class FullTime : public Employee {
double salary;
public:
FullTime(string n,int i,double s):Employee(n,i),salary(s){}
double calculateSalary() override {return salary;}
};
class PartTime : public Employee {
double rate; int hours;
public:
PartTime(string n,int i,double r,int h):Employee(n,i),rate(r),hours(h){}
double calculateSalary() override {return rate*hours;}
};
int main() {
Employee* e[]={new FullTime("Alice",1,50000),new PartTime("Bob",2,200,80)};
if(auto x:e){x-display();delete x;}
return 0;
}
Show Solution ▾
#include
using namespace std;
class Cylinder;
class Box {
double l,w,h;
public:
Box(double l,double w,double h):l(l),w(w),h(h){}
friend void compare(Box b,Cylinder c);
};
class Cylinder {
double r,h;
public:
Cylinder(double r,double h):r(r),h(h){}
friend void compare(Box b,Cylinder c);
};
void compare(Box b, Cylinder c) {
double bv=b.l*b.w*b.h, cv=3.14*c.r*c.r*c.h;
cout<<(bvcv?"Box":"Cylinder")<<" is larger\n";
}
int main(){Box b(3,4,5);Cylinder c(3,7);compare(b,c); return 0;
}
Show Solution ▾
#include
using namespace std;
class Media {
protected: string title; int duration;
public:
Media(string t,int d):title(t),duration(d){}
virtual void play()=0;
virtual void getInfo()=0;
virtual ~Media(){}
};
class Song : public Media {
string artist;
public:
Song(string t,int d,string a):Media(t,d),artist(a){}
void play() override { cout<<"Playing song: "<<title<<" by "<<artist<<"\n"; }
void getInfo() override { cout<<title<<" | "<<duration<<"s\n"; }
};
class Movie : public Media {
string director;
public:
Movie(string t,int d,string dir):Media(t,d),director(dir){}
void play() override { cout<<"Playing movie: "<<title<<" dir:"<<director<<"\n"; }
void getInfo() override { cout<<title<<" | "<<duration<<"min\n"; }
};
int main(){
Media* lib[]={new Song("Blinding Lights",200,"Weeknd"),new Movie("Inception",148,"Nolan")};
if(auto m:lib){m-play();delete m;}
return 0;
}
Show Solution ▾
#include
using namespace std;
// WRONG (ambiguous):
class A {public: void greet(){cout<<"Hello from A\n";}};
class B:public A{};
class C:public A{};
class D:public B,public C{};
// D d; d.greet(); // ERROR: ambiguous
// CORRECT (virtual inheritance):
class A {public: void greet(){cout<<"Hello from A\n";}};
class B: virtual public A{};
class C: virtual public A{};
class D: public B, public C{};
int main(){D d; d.greet();} // OK: one copy of A
Show Solution ▾
#include
using namespace std;
class A {int x;
public:
A(int x):x(x){cout<<"A("<<x<<") created\n";}
~A(){cout<<"A destroyed\n";}};
class B:public A {int y;
public:
B(int x,int y):A(x),y(y){cout<<"B("<<y<<") created\n";}
~B(){cout<<"B destroyed\n";}};
class C:public B {int z;
public:
C(int x,int y,int z):B(x,y),z(z){cout<<"C("<<z<<") created\n";}
~C(){cout<<"C destroyed\n";}};
int main(){C obj(1,2,3);} // Output: A(1)-B(2)-C(3)-~C-~B-~A
Show Solution ▾
#include
using namespace std;
class LibraryItem {
int itemId; // private - only this class
protected:
string title, author; // accessible by derived
public:
LibraryItem(int id,string t,string a):itemId(id),title(t),author(a){}
int getId(){return itemId;}
virtual void display()=0;
virtual ~LibraryItem(){}
};
class Book : public LibraryItem {
string ISBN; int pages;
public:
Book(int id,string t,string a,string isbn,int p):LibraryItem(id,t,a),ISBN(isbn),pages(p){}
void display() override {
// title, author accessible (protected)
cout<<"Book: "<<title<<" by "<<author<<" ISBN:"<<ISBN<<"\n";
}
};
int main(){
LibraryItem* items[]={new Book(1,"C++ Primer","Lippman","978-x",976)};
if(auto i:items){i-display();delete i;}
return 0;
}
#include
using namespace std;
class IControllable {
public:
virtual void turnOn()=0;
virtual void turnOff()=0;
virtual string getStatus()=0;
virtual ~IControllable(){}};
class ISpeakable {
public:
virtual void speak()=0;
virtual ~ISpeakable(){}};
class SmartSpeaker:public IControllable,public ISpeakable{
bool on=false;
public:
void turnOn() override{on=true;cout<<"Speaker ON\n";}
void turnOff() override{on=false;cout<<"Speaker OFF\n";}
string getStatus() override{return on?"ON":"OFF";}
void speak() override{cout<<"Playing music!\n";}};
int main(){
SmartSpeaker s;
IControllable* ctrl=&s;
ISpeakable* spk=&s;
ctrl-turnOn();
spk-speak();
ctrl-turnOff();
return 0;
}
Show Solution ▾
#include
using namespace std;
class Person{
protected: string name; int age;
public:
Person(string n,int a):name(n),age(a){}
virtual void display()=0;
virtual ~Person(){}};
class Student:public Person{
int rollNo; float gpa; string branch;
public:
Student(string n,int a,int r,float g,string b):Person(n,a),rollNo(r),gpa(g),branch(b){}
void display() override{cout<<"Student:"<<name<<" Roll:"<<rollNo<<" GPA:"<<gpa<<"\n";}};
class Professor:public Person{
protected: string dept; double salary;
public:
Professor(string n,int a,string d,double s):Person(n,a),dept(d),salary(s){}
void display() override{cout<<"Prof:"<<name<<" Dept:"<<dept<<" Salary:"<<salary<<"\n";}};
class HOD:public Professor{
int numFaculty;
public:
HOD(string n,int a,string d,double s,int f):Professor(n,a,d,s),numFaculty(f){}
void display() override{Professor::display();cout<<" HOD of "<<dept<<", Faculty:"<<numFaculty<<"\n";}};
int main(){
Person* uni[]={new Student("Alice",20,101,9.1,"CS"),new Professor("Dr.Smith",45,"Math",80000),new HOD("Dr.Roy",50,"CS",100000,15)};
if(auto p:uni){p-display();delete p;}
return 0;
}
#include
using namespace std;
class WeatherStation; // forward declaration
class Temperature{
double celsius;
public:
Temperature(double c):celsius(c){}
inline double toCelsius(){return celsius;}
inline double toFahrenheit(){return celsius*9/5+32;}
inline double toKelvin(){return celsius+273.15;}
friend void printReport(WeatherStation ws);};
class WeatherStation{
string location;
Temperature reading;
public:
WeatherStation(string loc,double c):location(loc),reading(c){}
friend void printReport(WeatherStation ws);};
void printReport(WeatherStation ws){
cout<<"Location: "<<ws.location<<"\n";
cout<<"Celsius: "<<ws.reading.toCelsius()<<"\n";
cout<<"Fahrenheit: "<<ws.reading.toFahrenheit()<<"\n";
cout<<"Kelvin: "<<ws.reading.toKelvin()<<"\n";}
int main(){
WeatherStation w1("Delhi",38),w2("Arctic",-40);
printReport(w1);printReport(w2); return 0;
}
Complete Programs — Full Execution Flow
Every program below is 100% compilable with full headers, main(), and expected output. Study the dry runs to understand memory execution step-by-step.
#include
using namespace std;
#include <iostream>
using namespace std;
class Vehicle {
protected:
string brand;
int speed;
public:
Vehicle(string b, int s) : brand(b), speed(s) {
cout << "Vehicle constructor: " << brand << "\n";
}
virtual void describe() {
cout << "Brand: " << brand << ", Speed: " << speed << "\n";
}
virtual ~Vehicle() { cout << "Vehicle destructor: " << brand << "\n"; }
};
class Car : public Vehicle {
protected:
string fuelType;
public:
Car(string b, int s, string f) : Vehicle(b, s), fuelType(f) {
cout << "Car constructor: " << fuelType << "\n";
}
void describe() override {
Vehicle::describe();
cout << "Fuel: " << fuelType << "\n";
}
~Car() { cout << "Car destructor\n"; }
};
class ElectricCar : public Car {
int batteryRange;
public:
ElectricCar(string b, int s, int r)
: Car(b, s, "Electric"), batteryRange(r) {
cout << "ElectricCar constructor: range=" << batteryRange << "\n";
}
void describe() override {
Car::describe();
cout << "Battery Range: " << batteryRange << " km\n";
}
~ElectricCar() { cout << "ElectricCar destructor\n"; }
};
int main() {
cout << "=== Creating ElectricCar ===\n";
ElectricCar* ec = new ElectricCar("Tesla", 200, 500);
cout << "\n=== Calling describe() ===\n";
ec-describe();
cout << "\n=== Deleting via base pointer ===\n";
Vehicle* vp = ec;
delete vp;
return 0;
}
=== Creating ElectricCar ===
Vehicle constructor: Tesla
Car constructor: Electric
ElectricCar constructor: range=500
=== Calling describe() ===
Brand: Tesla, Speed: 200
Fuel: Electric
Battery Range: 500 km
=== Deleting via base pointer ===
ElectricCar destructor
Car destructor
Vehicle destructor: Tesla
ElectricCar* ec = new ElectricCar("Tesla",200,500) — heap
allocation begins. Before ElectricCar body runs, it must first call
Car("Tesla",200,"Electric").ec-describe() — virtual dispatch: actual object is
ElectricCar, so ElectricCar::describe() runs. It calls Car::describe() which calls
Vehicle::describe() — chaining upward.delete vp where vp is Vehicle* pointing to ElectricCar.
Because ~Vehicle() is virtual → runtime checks VTable → calls ~ElectricCar() FIRST, then
~Car(), then ~Vehicle(). Correct cleanup order!Derived(args) : Base(base_args) {}#include
using namespace std;
#include <iostream>
#include <cmath>
using namespace std;
class Shape { // Abstract base class
public:
string color;
Shape(string c) : color(c) {}
virtual double area() = 0; // pure virtual
virtual double perimeter() = 0; // pure virtual
virtual void display() {
cout << "[" << color << "] ";
}
virtual ~Shape() {}
};
class Circle : public Shape {
double radius;
public:
Circle(string c, double r) : Shape(c), radius(r) {}
double area() override { return 3.14159 * radius * radius; }
double perimeter() override { return 2 * 3.14159 * radius; }
void display() override {
Shape::display();
cout << "Circle r=" << radius
<< " | Area=" << area()
<< " | Perimeter=" << perimeter() << "\n";
}
};
class Rectangle : public Shape {
double width, height;
public:
Rectangle(string c, double w, double h)
: Shape(c), width(w), height(h) {}
double area() override { return width * height; }
double perimeter() override { return 2 * (width + height); }
void display() override {
Shape::display();
cout << "Rect " << width << "x" << height
<< " | Area=" << area()
<< " | Perimeter=" << perimeter() << "\n";
}
};
class Triangle : public Shape {
double a, b, c;
public:
Triangle(string col, double a, double b, double c)
: Shape(col), a(a), b(b), c(c) {}
double perimeter() override { return a + b + c; }
double area() override {
double s = perimeter() / 2; // Heron's formula
return sqrt(s*(s-a)*(s-b)*(s-c));
}
void display() override {
Shape::display();
cout << "Triangle " << a << "," << b << "," << c
<< " | Area=" << area() << "\n";
}
};
int main() {
Shape* shapes[] = {
new Circle("Red", 5),
new Rectangle("Blue", 4, 6),
new Triangle("Green", 3, 4, 5)
};
double totalArea = 0;
cout << "=== Shape Report ===\n";
if(Shape* s : shapes) {
s-display();
totalArea += s-area();
}
cout << "Total Area: " << totalArea << "\n";
if(Shape* s : shapes) delete s;
return 0;
}
=== Shape Report ===
[Red] Circle r=5 | Area=78.5397 | Perimeter=31.4159
[Blue] Rect 4x6 | Area=24 | Perimeter=20
[Green] Triangle 3,4,5 | Area=6 | Perimeter=12
Total Area: 108.54
Shape* shapes[] = {...} — array of BASE CLASS POINTERS. Each
pointer holds address of a DIFFERENT derived object on heap. This is the foundation of
polymorphism.if(Shape* s : shapes) s-display() — same code, different
behavior for each. Virtual dispatch checks VTable at runtime. Circle → Circle::display,
Rectangle → Rectangle::display, Triangle → Triangle::display.totalArea += s-area() — area() is pure virtual in Shape.
Each derived class provides its own formula. The BASE class code calls the DERIVED formula —
this is runtime polymorphism in action.if(Shape* s:shapes) delete s — virtual destructor ensures
each derived destructor runs, preventing memory leaks.BaseClass* arr[] = {new D1(), new D2()}; if(auto p:arr){p-method(); delete p;}
#include
using namespace std;
#include <iostream>
using namespace std;
class Celsius; // Forward declaration
class Fahrenheit {
double fahr;
public:
Fahrenheit(double f) : fahr(f) {}
inline double getFahr() const { return fahr; }
friend void printComparison(Fahrenheit f, Celsius c);
};
class Celsius {
double cel;
public:
Celsius(double c) : cel(c) {}
inline double getCel() const { return cel; }
inline double toFahrenheit() const { return cel * 9.0/5.0 + 32; }
friend void printComparison(Fahrenheit f, Celsius c);
};
// Friend function — accesses BOTH classes' private members
void printComparison(Fahrenheit f, Celsius c) {
cout << "Fahrenheit value : " << f.fahr << "°F\n";
cout << "Celsius value : " << c.cel << "°C\n";
cout << "Celsius as °F : " << c.toFahrenheit() << "°F\n";
cout << "Are they equal? : "
<< (f.fahr == c.toFahrenheit() ? "YES" : "NO") << "\n";
}
int main() {
Fahrenheit boiling(212.0);
Celsius water(100.0);
printComparison(boiling, water);
cout << "\n";
Fahrenheit freezing(32.0);
Celsius ice(0.0);
printComparison(freezing, ice);
return 0;
}
Fahrenheit value : 212°F
Celsius value : 100°C
Celsius as °F : 212°F
Are they equal? : YES
Fahrenheit value : 32°F
Celsius value : 0°C
Celsius as °F : 32°F
Are they equal? : YES
class Celsius; — Forward declaration. Fahrenheit needs to
mention Celsius in friend declaration, but Celsius isn't fully defined yet. Forward
declaration tells the compiler "this class exists, full definition comes later."friend void printComparison(Fahrenheit, Celsius) declared
INSIDE BOTH classes. Both grant access to their private members to this single function.
f.fahr accesses Fahrenheit's private
member directly (NOT via getter). Same for c.cel. This is the ONLY place
outside these classes where this is possible.inline double toFahrenheit() — body is inside class
definition, so it's automatically inline. No function call overhead.