Practice Questions — Polymorphism - Virtual Functions and Operator Overloading
← Back to NotesTopic-Specific Questions
Question 1
Easy
What is the output of the following code?
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() { cout << "Animal sound" << endl; }
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void sound() override { cout << "Bark" << endl; }
};
int main() {
Animal* a = new Dog();
a->sound();
delete a;
return 0;
}The pointer type is Animal*, but the actual object is Dog. sound() is virtual.
BarkQuestion 2
Easy
What is the output?
#include <iostream>
using namespace std;
class Calc {
public:
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
};
int main() {
Calc c;
cout << c.add(3, 4) << endl;
cout << c.add(3.0, 4.0) << endl;
return 0;
}The compiler selects the matching overloaded function based on argument types.
77Question 3
Easy
What is the output?
#include <iostream>
using namespace std;
class A {
public:
virtual void show() { cout << "A" << endl; }
virtual ~A() {}
};
class B : public A {
public:
void show() override { cout << "B" << endl; }
};
class C : public B {
public:
void show() override { cout << "C" << endl; }
};
int main() {
A* obj = new C();
obj->show();
delete obj;
return 0;
}C extends B extends A. The actual object is C. show() is virtual.
CQuestion 4
Easy
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
void greet() { cout << "Hello from Base" << endl; }
};
class Derived : public Base {
};
int main() {
Base* b = new Derived();
b->greet();
delete b;
return 0;
}greet() is NOT virtual. Derived does not override it.
Hello from BaseQuestion 5
Easy
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
void show() { cout << "Base" << endl; }
};
class Derived : public Base {
public:
void show() { cout << "Derived" << endl; }
};
int main() {
Base* b = new Derived();
b->show();
Derived* d = new Derived();
d->show();
delete b;
delete d;
return 0;
}show() is NOT virtual. The call depends on the pointer type.
BaseDerivedQuestion 6
Medium
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void display() { cout << "Base::display" << endl; }
void show() { cout << "Base::show" << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void display() override { cout << "Derived::display" << endl; }
void show() { cout << "Derived::show" << endl; }
};
int main() {
Base* b = new Derived();
b->display();
b->show();
delete b;
return 0;
}display() is virtual but show() is not. How does this affect the call?
Derived::displayBase::showQuestion 7
Medium
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
int x = 10;
virtual void show() { cout << x << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
int x = 20;
void show() override { cout << x << endl; }
};
int main() {
Base* b = new Derived();
cout << b->x << endl;
b->show();
delete b;
return 0;
}Data members are not polymorphic. Virtual functions are polymorphic.
1020Question 8
Medium
What is the output?
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() { cout << "Shape" << endl; }
virtual ~Shape() {}
};
class Circle : public Shape {
public:
void draw() override { cout << "Circle" << endl; }
};
void render(Shape s) {
s.draw();
}
int main() {
Circle c;
render(c);
return 0;
}The function takes Shape by value, not by reference or pointer.
ShapeQuestion 9
Medium
What is the output?
#include <iostream>
using namespace std;
class Complex {
int real, imag;
public:
Complex(int r = 0, int i = 0) : real(r), imag(i) {}
Complex operator+(const Complex& c) const {
return Complex(real + c.real, imag + c.imag);
}
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real << "+" << c.imag << "i";
return os;
}
};
int main() {
Complex a(3, 4), b(1, 2);
Complex c = a + b;
cout << c << endl;
return 0;
}a + b calls operator+(b) on a. The << operator is a friend function.
4+6iQuestion 10
Medium
What is the output?
#include <iostream>
using namespace std;
class Counter {
int val;
public:
Counter(int v) : val(v) {}
Counter& operator++() { ++val; return *this; }
Counter operator++(int) { Counter t = *this; ++val; return t; }
friend ostream& operator<<(ostream& os, const Counter& c) {
os << c.val; return os;
}
};
int main() {
Counter c(5);
cout << ++c << endl;
cout << c++ << endl;
cout << c << endl;
return 0;
}Prefix ++ increments first then returns. Postfix ++ returns old value then increments.
667Question 11
Medium
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void test() { cout << "Base::test" << endl; }
virtual ~Base() {}
};
class Mid : public Base {
public:
void test() override { cout << "Mid::test" << endl; }
};
class Leaf : public Mid {
public:
void test() override { cout << "Leaf::test" << endl; }
};
int main() {
Base* b1 = new Mid();
Base* b2 = new Leaf();
Mid* m1 = new Leaf();
b1->test();
b2->test();
m1->test();
delete b1; delete b2; delete m1;
return 0;
}All calls resolve to the actual object type because test() is virtual throughout.
Mid::testLeaf::testLeaf::testQuestion 12
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base()" << endl; }
virtual ~Base() { cout << "~Base()" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived()" << endl; }
~Derived() { cout << "~Derived()" << endl; }
};
int main() {
Base* b = new Derived();
delete b;
return 0;
}The destructor is virtual. Both destructors should run in reverse order.
Base()Derived()~Derived()~Base()Question 13
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { cout << "Base" << endl; display(); }
virtual void display() { cout << "Base::display" << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void display() override { cout << "Derived::display" << endl; }
};
int main() {
Base* b = new Derived();
b->show();
delete b;
return 0;
}show() is inherited from Base. But display() is overridden. When show() calls display(), which version runs?
BaseDerived::displayQuestion 14
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Base ctor" << endl;
init();
}
virtual void init() { cout << "Base::init" << endl; }
virtual ~Base() {}
};
class Derived : public Base {
int val;
public:
Derived() : val(42) {
cout << "Derived ctor, val=" << val << endl;
}
void init() override { cout << "Derived::init, val=" << val << endl; }
};
int main() {
Derived d;
return 0;
}During Base constructor, the vtable points to Base's vtable, not Derived's. What does init() call?
Base ctorBase::initDerived ctor, val=42Question 15
Hard
What is the output?
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() = 0;
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void sound() override { cout << "Bark" << endl; }
};
class GoldenRetriever : public Dog {
public:
void sound() override { cout << "Friendly Bark" << endl; }
};
int main() {
Animal* a1 = new Dog();
Animal* a2 = new GoldenRetriever();
Dog* d1 = new GoldenRetriever();
a1->sound();
a2->sound();
d1->sound();
delete a1; delete a2; delete d1;
return 0;
}sound() is pure virtual in Animal. Both Dog and GoldenRetriever override it.
BarkFriendly BarkFriendly BarkQuestion 16
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void func(int x) { cout << "Base::func(int) " << x << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void func(int x) override { cout << "Derived::func(int) " << x << endl; }
void func(double x) { cout << "Derived::func(double) " << x << endl; }
};
int main() {
Base* b = new Derived();
b->func(10);
b->func(10.5);
delete b;
return 0;
}Base only declares func(int). func(double) in Derived is not visible through a Base pointer.
Derived::func(int) 10Derived::func(int) 10Question 17
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() const { cout << "Base" << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void show() { cout << "Derived" << endl; }
};
int main() {
Base* b = new Derived();
b->show();
delete b;
return 0;
}Base::show() is const but Derived::show() is not const. Are they the same signature?
BaseQuestion 18
Hard
What is the output?
#include <iostream>
using namespace std;
class Animal {
public:
virtual ~Animal() {}
};
class Dog : public Animal {};
class Cat : public Animal {};
int main() {
Animal* a = new Dog();
Dog* d = dynamic_cast<Dog*>(a);
Cat* c = dynamic_cast<Cat*>(a);
cout << (d != nullptr) << endl;
cout << (c != nullptr) << endl;
delete a;
return 0;
}dynamic_cast returns nullptr when the cast is invalid for pointers.
10Mixed & Application Questions
Question 1
Easy
What is the output?
#include <iostream>
using namespace std;
class Printer {
public:
void print(int x) { cout << "int: " << x << endl; }
void print(double x) { cout << "double: " << x << endl; }
void print(const string& x) { cout << "string: " << x << endl; }
};
int main() {
Printer p;
p.print(42);
p.print(3.14);
p.print(string("Arjun"));
return 0;
}Three overloaded print functions with different parameter types.
int: 42double: 3.14string: ArjunQuestion 2
Easy
What is the output?
#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
bool operator==(const Point& p) const {
return x == p.x && y == p.y;
}
};
int main() {
Point a(3, 4), b(3, 4), c(1, 2);
cout << (a == b) << endl;
cout << (a == c) << endl;
return 0;
}The == operator compares both x and y values.
10Question 3
Easy
What is the output?
#include <iostream>
using namespace std;
class Vehicle {
public:
virtual void start() { cout << "Vehicle" << endl; }
virtual ~Vehicle() {}
};
class Car : public Vehicle {
public:
void start() override { cout << "Car" << endl; }
};
class Bike : public Vehicle {
public:
void start() override { cout << "Bike" << endl; }
};
int main() {
Vehicle* v[] = { new Car(), new Bike(), new Vehicle() };
for (int i = 0; i < 3; i++) {
v[i]->start();
delete v[i];
}
return 0;
}An array of base class pointers, each pointing to a different type.
CarBikeVehicleQuestion 4
Easy
What is the difference between compile-time and runtime polymorphism in C++?
Think about when the function to call is decided: compilation or execution.
Compile-time polymorphism (static binding) is resolved by the compiler. It includes function overloading and operator overloading. Runtime polymorphism (dynamic binding) is resolved at execution time using virtual functions and the vtable mechanism. It requires inheritance and the virtual keyword.
Question 5
Medium
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual void func() { cout << "Base" << endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void func() override { cout << "Derived" << endl; }
};
int main() {
Derived d;
Base& ref = d;
ref.func();
Base b = d; // Copy by value
b.func();
return 0;
}References preserve polymorphism. Copying by value does not.
DerivedBaseQuestion 6
Medium
What is the output?
#include <iostream>
using namespace std;
class Matrix {
int data[2][2];
public:
Matrix(int a, int b, int c, int d) {
data[0][0]=a; data[0][1]=b; data[1][0]=c; data[1][1]=d;
}
Matrix operator+(const Matrix& m) const {
return Matrix(data[0][0]+m.data[0][0], data[0][1]+m.data[0][1],
data[1][0]+m.data[1][0], data[1][1]+m.data[1][1]);
}
friend ostream& operator<<(ostream& os, const Matrix& m) {
os << m.data[0][0] << " " << m.data[0][1] << endl;
os << m.data[1][0] << " " << m.data[1][1];
return os;
}
};
int main() {
Matrix a(1,2,3,4), b(5,6,7,8);
Matrix c = a + b;
cout << c << endl;
return 0;
}The + operator adds corresponding elements of two 2x2 matrices.
6 810 12Question 7
Medium
What is the vtable and vptr mechanism? How does it enable runtime polymorphism?
Think about what the compiler generates for classes with virtual functions.
When a class has at least one virtual function, the compiler creates a vtable (virtual function table) for that class, which is an array of function pointers. Each object of that class contains a hidden vptr (virtual pointer) that points to its class's vtable. When a virtual function is called through a base pointer, the program follows the vptr to the vtable and calls the function pointer at the appropriate slot. This is how the correct overridden function is called at runtime.
Question 8
Medium
What is the output?
#include <iostream>
using namespace std;
class Num {
int val;
public:
Num(int v) : val(v) {}
Num operator-() const { return Num(-val); }
Num operator-(const Num& n) const { return Num(val - n.val); }
friend ostream& operator<<(ostream& os, const Num& n) {
os << n.val; return os;
}
};
int main() {
Num a(10), b(3);
cout << -a << endl;
cout << (a - b) << endl;
return 0;
}Unary minus (negation) and binary minus (subtraction) are different operators.
-107Question 9
Hard
What is the output?
#include <iostream>
using namespace std;
class A {
public:
virtual void f() { cout << "A::f" << endl; }
void g() { cout << "A::g" << endl; f(); }
virtual ~A() {}
};
class B : public A {
public:
void f() override { cout << "B::f" << endl; }
void g() { cout << "B::g" << endl; f(); }
};
int main() {
A* p = new B();
p->g();
cout << "---" << endl;
B* q = new B();
q->g();
delete p; delete q;
return 0;
}g() is NOT virtual. Through A*, A::g() runs. But f() inside g() IS virtual.
A::gB::f---B::gB::fQuestion 10
Hard
What is the output?
#include <iostream>
using namespace std;
class Base {
public:
virtual Base* clone() {
cout << "Base clone" << endl;
return new Base(*this);
}
virtual ~Base() {}
};
class Derived : public Base {
int x;
public:
Derived(int x) : x(x) {}
Derived* clone() override {
cout << "Derived clone, x=" << x << endl;
return new Derived(*this);
}
};
int main() {
Base* b = new Derived(42);
Base* copy = b->clone();
delete b;
delete copy;
return 0;
}Derived::clone() returns Derived* instead of Base*. Is this a valid override?
Derived clone, x=42Question 11
Medium
Why must the << operator be overloaded as a friend function (or non-member function) rather than a member function?
Think about which object is the left operand of <<.
When you write cout << obj, the left operand is cout (an ostream object), not your class object. If << were a member function of your class, the syntax would be obj << cout (your object on the left), which is backwards. A friend function takes ostream& as the first parameter and your object as the second, matching the natural cout << obj syntax.
Question 12
Hard
What is the output?
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
public:
void draw() override { cout << "Circle" << endl; }
};
class Square : public Shape {
public:
void draw() override { cout << "Square" << endl; }
};
int main() {
Shape* shapes[] = { new Circle(), new Square(), new Circle() };
for (int i = 0; i < 3; i++) {
shapes[i]->draw();
}
for (int i = 0; i < 3; i++) delete shapes[i];
return 0;
}Pure virtual function. Each derived class provides its own implementation.
CircleSquareCircleQuestion 13
Hard
What is the output?
#include <iostream>
using namespace std;
class SafeArray {
int arr[5];
public:
SafeArray() { for(int i=0;i<5;i++) arr[i]=i*10; }
int& operator[](int i) {
if(i<0||i>=5) { cout<<"OOB"<<endl; return arr[0]; }
return arr[i];
}
};
int main() {
SafeArray sa;
cout << sa[2] << endl;
sa[3] = 99;
cout << sa[3] << endl;
cout << sa[10] << endl;
return 0;
}The [] operator returns a reference, allowing both read and write. Index 10 is out of bounds.
2099OOB0Multiple Choice Questions
MCQ 1
Which keyword enables runtime polymorphism in C++?
Answer: B
B is correct. The
B is correct. The
virtual keyword tells the compiler to use dynamic dispatch (vtable lookup) instead of static binding. Without it, the function called depends on the pointer type, not the actual object type.MCQ 2
Which of the following is compile-time polymorphism?
Answer: B
B is correct. Function overloading is resolved at compile time based on argument types and count. Virtual functions, dynamic dispatch, and pure virtual functions are all related to runtime polymorphism.
B is correct. Function overloading is resolved at compile time based on argument types and count. Virtual functions, dynamic dispatch, and pure virtual functions are all related to runtime polymorphism.
MCQ 3
Which operator CANNOT be overloaded in C++?
Answer: C
C is correct. The scope resolution operator
C is correct. The scope resolution operator
:: cannot be overloaded. Other operators that cannot be overloaded include ., .*, ?:, sizeof, and typeid.MCQ 4
What is the purpose of a virtual destructor?
Answer: B
B is correct. Without a virtual destructor, deleting a derived object through a base pointer only calls the base destructor. A virtual destructor ensures the correct destructor chain runs, preventing resource leaks.
B is correct. Without a virtual destructor, deleting a derived object through a base pointer only calls the base destructor. A virtual destructor ensures the correct destructor chain runs, preventing resource leaks.
MCQ 5
What distinguishes prefix ++ from postfix ++ in operator overloading?
Answer: B
B is correct. Prefix
B is correct. Prefix
operator++() takes no parameters and returns a reference. Postfix operator++(int) takes a dummy int parameter (never used) and returns a copy of the old value.MCQ 6
What is the slicing problem in C++?
Answer: B
B is correct. When a derived object is passed by value to a function expecting a base class, only the base portion is copied. The derived class data members and vtable pointer are lost (sliced off).
B is correct. When a derived object is passed by value to a function expecting a base class, only the base portion is copied. The derived class data members and vtable pointer are lost (sliced off).
MCQ 7
What does dynamic_cast return when a pointer cast fails?
Answer: B
B is correct. For pointer casts,
B is correct. For pointer casts,
dynamic_cast returns nullptr on failure. For reference casts, it throws std::bad_cast. This makes pointer-based dynamic_cast safe to check with an if statement.MCQ 8
How much extra memory does a vtable pointer add to each object?
Answer: C
C is correct. Each object with virtual functions has one hidden vptr (virtual pointer), which is one pointer in size (4 bytes on 32-bit, 8 bytes on 64-bit systems). The vtable itself is per-class, not per-object, so its size does not affect object size.
C is correct. Each object with virtual functions has one hidden vptr (virtual pointer), which is one pointer in size (4 bytes on 32-bit, 8 bytes on 64-bit systems). The vtable itself is per-class, not per-object, so its size does not affect object size.
MCQ 9
Which operators MUST be overloaded as member functions?
Answer: C
C is correct. The assignment (
C is correct. The assignment (
=), subscript ([]), function call (()), and arrow (->) operators must be overloaded as non-static member functions. All other operators can be either member or non-member.MCQ 10
What does the override keyword do in C++11?
Answer: B
B is correct.
B is correct.
override is a compile-time check. If the function signature does not match any virtual function in the base class, the compiler reports an error. This catches subtle bugs like const-mismatch or typos.MCQ 11
What happens when a virtual function is called inside a base class constructor?
Answer: B
B is correct. During the base class constructor, the vtable pointer still points to the base class's vtable (the derived part is not yet constructed). So the base version of the virtual function is called. This is different from Java.
B is correct. During the base class constructor, the vtable pointer still points to the base class's vtable (the derived part is not yet constructed). So the base version of the virtual function is called. This is different from Java.
MCQ 12
What is RTTI in C++?
Answer: A
A is correct. RTTI (Runtime Type Information) is the mechanism that enables
A is correct. RTTI (Runtime Type Information) is the mechanism that enables
dynamic_cast and typeid to work at runtime. It requires at least one virtual function in the class hierarchy. Some compilers allow disabling RTTI with -fno-rtti.MCQ 13
What is the output?
class A {
public:
virtual void f() { cout << "A"; }
virtual ~A() {}
};
class B : public A {
public:
void f() override { cout << "B"; }
};
void test(A a) { a.f(); }
int main() { test(B()); }Answer: A
A is correct. The function
A is correct. The function
test() takes A by value. When B() is passed, slicing occurs: only the A portion is copied. The sliced copy's vtable points to A's vtable, so A::f() is called.MCQ 14
Which of the following is true about pure virtual functions?
Answer: C
C is correct. A class with at least one pure virtual function (
C is correct. A class with at least one pure virtual function (
= 0) is abstract and cannot be instantiated. Contrary to option B, a pure virtual function CAN have a definition in the base class (callable via Base::func()).MCQ 15
What does the final keyword do when applied to a virtual function?
Answer: B
B is correct.
B is correct.
final on a virtual function prevents any derived class from overriding it further. On a class, final prevents inheritance. They serve different purposes depending on context.MCQ 16
What is the minimum requirement for dynamic_cast to work?
Answer: B
B is correct.
B is correct.
dynamic_cast uses RTTI, which requires the vtable/vptr mechanism. A class must have at least one virtual function for the compiler to generate RTTI. Without it, dynamic_cast causes a compilation error.MCQ 17
What is a covariant return type in C++?
Answer: B
B is correct. If a base class virtual function returns
B is correct. If a base class virtual function returns
Base*, the derived class override can return Derived*. This is called a covariant return type. The return type must be a pointer or reference to a class derived from the original return type.Coding Challenges
Challenge 1: Shape Area Calculator with Virtual Functions
EasyCreate an abstract Shape class with a pure virtual area() method. Create Circle (radius), Rectangle (width, height), and Triangle (base, height) subclasses. Store pointers in a Shape* array and compute total area using a loop.
Sample Input
Circle radius=5, Rectangle 4x6, Triangle base=3 height=8
Sample Output
Circle area: 78.54
Rectangle area: 24.00
Triangle area: 12.00
Total area: 114.54
Use virtual functions. Use override keyword. Include virtual destructor. Do not pass objects by value.
#include <iostream>
#include <cmath>
using namespace std;
class Shape {
public:
virtual double area() const = 0;
virtual string name() const = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return M_PI * radius * radius; }
string name() const override { return "Circle"; }
};
class Rectangle : public Shape {
double w, h;
public:
Rectangle(double w, double h) : w(w), h(h) {}
double area() const override { return w * h; }
string name() const override { return "Rectangle"; }
};
class Triangle : public Shape {
double base, height;
public:
Triangle(double b, double h) : base(b), height(h) {}
double area() const override { return 0.5 * base * height; }
string name() const override { return "Triangle"; }
};
int main() {
Shape* shapes[] = { new Circle(5), new Rectangle(4, 6), new Triangle(3, 8) };
double total = 0;
for (int i = 0; i < 3; i++) {
double a = shapes[i]->area();
printf("%s area: %.2f\n", shapes[i]->name().c_str(), a);
total += a;
}
printf("Total area: %.2f\n", total);
for (int i = 0; i < 3; i++) delete shapes[i];
return 0;
}Challenge 2: Complex Number Class with Full Operator Overloading
MediumCreate a Complex class with operator overloading for +, -, *, ==, !=, prefix ++, postfix ++, unary -, <<, and >>. Test all operators.
Sample Input
a = (3, 4), b = (1, 2)
Sample Output
a + b = 4+6i
a - b = 2+2i
a * b = -5+10i
a == b: 0
-a = -3-4i
Use const references for parameters. Return by value for binary operators. Use friend for << and >>.
#include <iostream>
using namespace std;
class Complex {
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
Complex operator+(const Complex& c) const { return Complex(real+c.real, imag+c.imag); }
Complex operator-(const Complex& c) const { return Complex(real-c.real, imag-c.imag); }
Complex operator*(const Complex& c) const {
return Complex(real*c.real - imag*c.imag, real*c.imag + imag*c.real);
}
Complex operator-() const { return Complex(-real, -imag); }
bool operator==(const Complex& c) const { return real==c.real && imag==c.imag; }
bool operator!=(const Complex& c) const { return !(*this == c); }
Complex& operator++() { ++real; return *this; }
Complex operator++(int) { Complex t = *this; ++real; return t; }
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
friend istream& operator>>(istream& is, Complex& c) {
is >> c.real >> c.imag;
return is;
}
};
int main() {
Complex a(3, 4), b(1, 2);
cout << "a + b = " << (a + b) << endl;
cout << "a - b = " << (a - b) << endl;
cout << "a * b = " << (a * b) << endl;
cout << "a == b: " << (a == b) << endl;
cout << "-a = " << -a << endl;
return 0;
}Challenge 3: Payment Processor with dynamic_cast
MediumCreate a Payment base class with virtual process(double). Create CreditCard (has cardNumber), UPI (has upiId), and NetBanking subclasses. Write a processAndLog function that uses dynamic_cast to detect the payment type and log extra details.
Sample Input
Amount = 1500.0
Sample Output
Credit Card: Processing 1500 with card ending 4321
UPI: Processing 1500 via ravi@upi
Net Banking: Processing 1500 via bank transfer
Unknown payment type for amount 1500
Use dynamic_cast for safe downcasting. Use virtual destructor. Demonstrate nullptr check.
#include <iostream>
#include <string>
using namespace std;
class Payment {
public:
virtual void process(double amount) { cout << "Processing " << amount << endl; }
virtual ~Payment() {}
};
class CreditCard : public Payment {
string cardNum;
public:
CreditCard(string num) : cardNum(num) {}
void process(double amount) override {
cout << "Credit Card: Processing " << amount << " with card ending " << cardNum.substr(cardNum.size()-4) << endl;
}
};
class UPI : public Payment {
string upiId;
public:
UPI(string id) : upiId(id) {}
void process(double amount) override {
cout << "UPI: Processing " << amount << " via " << upiId << endl;
}
};
class NetBanking : public Payment {
public:
void process(double amount) override {
cout << "Net Banking: Processing " << amount << " via bank transfer" << endl;
}
};
void processAndLog(Payment* p, double amount) {
if (dynamic_cast<CreditCard*>(p) || dynamic_cast<UPI*>(p) || dynamic_cast<NetBanking*>(p)) {
p->process(amount);
} else {
cout << "Unknown payment type for amount " << amount << endl;
}
}
int main() {
Payment* payments[] = { new CreditCard("1234567890124321"), new UPI("ravi@upi"), new NetBanking(), new Payment() };
for (int i = 0; i < 4; i++) {
processAndLog(payments[i], 1500);
delete payments[i];
}
return 0;
}Challenge 4: SafeArray with [] Operator and Functor
MediumCreate a SafeArray class that wraps a dynamic array with bounds-checked [] operator. Also create a Transform functor class with operator() that applies a transformation to each element. Use them together to double every element.
Sample Input
Array: {1, 2, 3, 4, 5}, Transform: double each element
Sample Output
Before: 1 2 3 4 5
After: 2 4 6 8 10
Return reference from []. Throw out_of_range for invalid index. Functor takes int, returns int.
#include <iostream>
#include <stdexcept>
using namespace std;
class SafeArray {
int* data;
int sz;
public:
SafeArray(int n) : sz(n), data(new int[n]()) {}
~SafeArray() { delete[] data; }
int& operator[](int i) {
if (i < 0 || i >= sz) throw out_of_range("Index out of bounds");
return data[i];
}
int size() const { return sz; }
};
class Transform {
int factor;
public:
Transform(int f) : factor(f) {}
int operator()(int x) const { return x * factor; }
};
int main() {
SafeArray arr(5);
for (int i = 0; i < 5; i++) arr[i] = i + 1;
cout << "Before:";
for (int i = 0; i < 5; i++) cout << " " << arr[i];
cout << endl;
Transform doubler(2);
for (int i = 0; i < 5; i++) arr[i] = doubler(arr[i]);
cout << "After:";
for (int i = 0; i < 5; i++) cout << " " << arr[i];
cout << endl;
return 0;
}Challenge 5: Employee Payroll with Virtual Functions and RTTI
HardCreate an abstract Employee class with pure virtual salary(). Create FullTime (monthly), PartTime (hourly rate * hours), Intern (stipend), and Contractor (daily rate * days) subclasses. Process an array of Employee* pointers. Use typeid to print the type of each employee. Compute total payroll.
Sample Input
FullTime=50000, PartTime=500/hr*80hrs, Intern=15000, Contractor=3000/day*20days
Sample Output
Arjun [FullTime]: 50000
Kavya [PartTime]: 40000
Ravi [Intern]: 15000
Priya [Contractor]: 60000
Total payroll: 165000
Use pure virtual functions. Use typeid for RTTI. Virtual destructor required. Do not slice objects.
#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;
class Employee {
protected:
string name;
public:
Employee(string n) : name(n) {}
virtual double salary() const = 0;
string getName() const { return name; }
virtual ~Employee() {}
};
class FullTime : public Employee {
double monthly;
public:
FullTime(string n, double m) : Employee(n), monthly(m) {}
double salary() const override { return monthly; }
};
class PartTime : public Employee {
double rate; int hours;
public:
PartTime(string n, double r, int h) : Employee(n), rate(r), hours(h) {}
double salary() const override { return rate * hours; }
};
class Intern : public Employee {
double stipend;
public:
Intern(string n, double s) : Employee(n), stipend(s) {}
double salary() const override { return stipend; }
};
class Contractor : public Employee {
double dailyRate; int days;
public:
Contractor(string n, double r, int d) : Employee(n), dailyRate(r), days(d) {}
double salary() const override { return dailyRate * days; }
};
int main() {
Employee* team[] = {
new FullTime("Arjun", 50000),
new PartTime("Kavya", 500, 80),
new Intern("Ravi", 15000),
new Contractor("Priya", 3000, 20)
};
double total = 0;
for (int i = 0; i < 4; i++) {
double s = team[i]->salary();
cout << team[i]->getName() << " [" << typeid(*team[i]).name() << "]: " << s << endl;
total += s;
}
cout << "Total payroll: " << total << endl;
for (int i = 0; i < 4; i++) delete team[i];
return 0;
}Need to Review the Concepts?
Go back to the detailed notes for this chapter.
Read Chapter NotesWant to learn C++ with a live mentor?
Explore our C++ Masterclass