0% found this document useful (0 votes)
6 views25 pages

oop_solutionsew d

This document provides model solutions to chapterwise past year questions on Object Oriented Programming, specifically focusing on C++ concepts. It covers advantages and disadvantages of OOP versus procedural programming, basic concepts of OOP, and various C++ programming topics including constructors, namespaces, and operator overloading. Each section includes sample code to illustrate the concepts discussed.

Uploaded by

Bipin Aryal
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views25 pages

oop_solutionsew d

This document provides model solutions to chapterwise past year questions on Object Oriented Programming, specifically focusing on C++ concepts. It covers advantages and disadvantages of OOP versus procedural programming, basic concepts of OOP, and various C++ programming topics including constructors, namespaces, and operator overloading. Each section includes sample code to illustrate the concepts discussed.

Uploaded by

Bipin Aryal
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Object Oriented Programming (CT/ENCT 151)

Chapterwise Solutions to Past Year Questions

TU, Institute of Engineering

This document provides model solutions to the chapterwise-sorted past year questions (Papers A–D, see com-
panion question file). Programs are kept simple and exam-appropriate; theory answers are concise.

Chapter 1: Introduction to Object Oriented Programming


Q1 (A) – Advantages of OOP & POP vs OOP
Advantages of OOP:
ˆ Data hiding/encapsulation → better security of data.
ˆ Code reusability through inheritance.
ˆ Polymorphism allows flexible, extensible code.
ˆ Easier maintenance and modular design (real-world modeling).
ˆ Reduces code duplication via templates and overloading.
Procedural vs Object Oriented Programming:
Procedural Programming Object Oriented Programming
Program divided into functions Program divided into objects/classes
Data is not protected (global access) Data is hidden/encapsulated within ob-
jects
Top-down approach Bottom-up approach
Adding new data/function is difficult Easy to add new data and functions via
inheritance
No proper way to model real world entities Naturally models real-world entities
Example: C Example: C++, Java
Sample code – POP style:
#include <iostream>
using namespace std;
float area; // global data, accessible everywhere

void calculateArea(float r){


area = 3.14 * r * r;
}
int main(){
calculateArea(5);
cout << "Area = " << area << endl;
return 0;
}

Sample code – OOP style:


#include <iostream>
using namespace std;
class Circle{
private:
float radius;
public:

1
Circle(float r){ radius = r; }
float area(){ return 3.14 * radius * radius; }
};
int main(){
Circle c(5);
cout << "Area = " << [Link]() << endl;
return 0;
}

Q1 (B) – Drawback of Procedural & Advantage of OOP


Drawbacks of procedural programming:
ˆ Global data can be accessed/modified from anywhere → no data security.
ˆ Difficult to relate data with the functions that operate on it.
ˆ Adding new data structures requires changing many functions.
ˆ Poor modeling of real-world problems.
Advantages of OOP are as listed in Q1(A) above (encapsulation, inheritance, polymorphism, reusability, data
security).
(Use the same two sample programs shown in Q1(A) – the global-variable version illustrates the procedural
drawback, and the Circle class version illustrates the OOP advantage of data hiding.)

Q1 (C) – Compare POP and OOP; Basic Concept of OOP


The comparison table is the same as in Q1(A).
Basic concepts of OOP:
ˆ Object – an instance of a class containing data and functions.
ˆ Class – a blueprint/template defining attributes and behaviors.
ˆ Encapsulation – binding data and functions together, hiding internal details.
ˆ Inheritance – acquiring properties of one class into another.
ˆ Polymorphism – same function name behaving differently (overloading/overriding).
ˆ Abstraction – showing only essential features, hiding implementation.

Q1 (D) – Benefits and Features of OOP


Benefits: code reusability, data security via encapsulation, easier debugging/maintenance, modularity, exten-
sibility through inheritance, real world modeling.
Features (concepts): class & object, encapsulation, abstraction, inheritance, polymorphism (overloading
and overriding), dynamic binding, message passing.

Chapter 2: Basics of C++ Programming


Q2 (A) – Default Arguments & Function Overloading Conflict
Default argument: a value automatically assigned to a parameter if the caller does not supply one. Used when
a function is usually called with the same value for some parameter, reducing the need for multiple overloaded
versions.
Conflict with overloading: If an overloaded function’s parameter list (after applying default arguments)
becomes ambiguous with another overload for some call, the compiler cannot decide which to call – this is an
ambiguity error. E.g. void f(int a, int b=0) and void f(int a) – calling f(5) is ambiguous.
#include <iostream>
#include <string>
using namespace std;

void printMessage(string message, int count = 1){


for(int i = 0; i < count; i++)
cout << message << endl;

2
}

int main(){
printMessage("Hello"); // uses default count = 1
printMessage("Welcome", 3); // prints 3 times
return 0;
}

Q2 (B) – Namespace
Namespace is a feature in C++ that provides a named scope to group related identifiers (variables, functions,
classes) and avoid name collisions, especially when combining code from multiple libraries.
Why needed: Large programs often use multiple libraries that may define identifiers with the same name.
Without namespaces, this causes naming conflicts. Namespaces let us use the same name in different scopes
without clashing.
#include <iostream>
using namespace std;

namespace First{
int value = 100;
void display(){ cout << "First::value = " << value << endl; }
}
namespace Second{
int value = 200;
void display(){ cout << "Second::value = " << value << endl; }
}

int main(){
First::display();
Second::display();
cout << "Directly: " << First::value + Second::value << endl;
return 0;
}

Q2 (C) – Inline Function & Function Overloading


When to prefer inline: When a function is small, called frequently, and does not contain loops/recursion –
the compiler replaces the function call with the function body directly, avoiding function-call overhead (stack
push/pop, jump).
#include <iostream>
using namespace std;

inline int square(int x){


return x * x;
}

int main(){
cout << "Square of 5 = " << square(5) << endl;
return 0;
}

Function overloading: Defining multiple functions with the same name but different parameter lists
(different number/type of parameters). The compiler chooses the correct version based on the arguments
passed (compile-time polymorphism).
#include <iostream>
using namespace std;

3
int add(int a, int b){ return a + b; }
double add(double a, double b){ return a + b; }
int add(int a, int b, int c){ return a + b + c; }

int main(){
cout << add(2, 3) << endl; // int version
cout << add(2.5, 3.5) << endl; // double version
cout << add(1, 2, 3) << endl; // three-arg version
return 0;
}

Q2 (D) – Reference Variable & Compound Interest Function


Reference variable: an alias (alternative name) for an already existing variable. Once initialized to refer to
a variable, it cannot be made to refer to another.
Syntax: data type &ref name = existing variable;
#include <iostream>
#include <cmath>
using namespace std;

// r has a default argument of 50


double compoundAmount(double p, int n, double r = 50){
return p * pow((1 + r/100), n);
}

int main(){
cout << "A (custom r) = " << compoundAmount(1000, 2, 10) << endl;
cout << "A (default r=50) = " << compoundAmount(1000, 2) << endl;
return 0;
}

Chapter 3: Objects and Classes


Q3 (A) – Constructors & Class Person
Constructor: a special member function with the same name as the class, automatically called when an object
is created, used to initialize data members. It has no return type.
Types of constructors:
ˆ Default constructor – takes no arguments.
ˆ Parameterized constructor – takes arguments to initialize members with specific values.
ˆ Copy constructor – creates an object as a copy of another existing object of the same class.

#include <iostream>
#include <string>
using namespace std;

class Person{
private:
string name, address;
int age;
long citizenship_number;
public:
// Parameterized constructor
Person(string n, int a, string addr, long cn){
name = n; age = a; address = addr;
if(age > 16)
citizenship_number = cn;

4
else
citizenship_number = 0;
}
void display(){
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Address: " << address << endl;
cout << "Citizenship No: " << citizenship_number << endl;
}
};

int main(){
Person p1("Ram", 20, "Kathmandu", 123456);
Person p2("Sita", 12, "Pokhara", 654321);
[Link]();
[Link]();
return 0;
}

Q3 (B) – Passing/Returning Objects, Friend Function & Friend Class


Passing objects to functions: An object can be passed by value (a copy is made, copy constructor invoked)
or by reference (&, no copy made – changes reflect in the original).
Returning objects from functions: A function can return an object of a class by value; a temporary
object is created and returned to the caller.
Friend class/function:
ˆ A class can be made friend of another when it needs to access the private/protected members of that
class directly (tight cooperation between two classes), declared as friend class ClassName; inside the
class granting access.
ˆ A specific member function of one class can be made a friend of another by declaring it as friend
returnType ClassName::funcName(...) inside the class granting access – this gives that one function
(not the whole class) access to private members.

#include <iostream>
using namespace std;

class B; // forward declaration

class A{
private:
int valA;
public:
A(int v) : valA(v) {}
// declare a specific member function of B as friend
friend void B::showBoth(A &a);
};

class B{
private:
int valB;
public:
B(int v) : valB(v) {}
void showBoth(A &a){
cout << "A’s private valA = " << [Link] << endl;
cout << "B’s valB = " << valB << endl;
}
};

5
Note: because B::showBoth uses A’s private member, B must be declared before A (or use forward declaration
as above) and A must friend that specific function of B.
Friend class example (object passed/returned):
#include <iostream>
using namespace std;

class Box{
private:
int length;
public:
Box(int l=0): length(l) {}
friend class BoxPrinter; // entire class is friend
};

class BoxPrinter{
public:
void print(Box b){ // object passed by value
cout << "Length = " << [Link] << endl;
}
Box makeBox(){ // returning an object
Box temp(10);
return temp;
}
};

int main(){
BoxPrinter bp;
Box b1 = [Link](); // object returned from function
[Link](b1); // object passed to function
return 0;
}

Q3 (C) – Constructor Types & Friend; Class Information with Swap


Types of constructors with syntax:
class Demo{
public:
Demo(); // default constructor
Demo(int x); // parameterized constructor
Demo(const Demo &obj); // copy constructor
};

Condition for friend class: when two classes are closely related and one needs direct access to the private/pro-
tected data of the other for efficiency or design reasons (e.g., operator overloading involving two classes, linked
data structures).
#include <iostream>
#include <string>
using namespace std;

class Information{
private:
string name, address;
public:
Information(string n, string a) : name(n), address(a) {}
void display(){
cout << "Name: " << name << ", Address: " << address << endl;
}
friend void swapInfo(Information &s1, Information &s2);

6
};

void swapInfo(Information &s1, Information &s2){


Information temp = s1;
s1 = s2;
s2 = temp;
}

int main(){
Information s1("Ram", "Kathmandu");
Information s2("Hari", "Pokhara");
cout << "Before swap:\n";
[Link](); [Link]();
swapInfo(s1, s2);
cout << "After swap:\n";
[Link](); [Link]();
return 0;
}

Q3 (D) – Friend Function as Bridge; Class Time with Aggregate Add


Friend function as bridge between two classes: A function declared as friend in two different classes
can access private members of both, allowing operations that combine data from both classes – e.g., adding an
object of class A to an object of class B.
#include <iostream>
using namespace std;

class Time{
private:
int hour, minute, second;
public:
Time(int h, int m, int s) : hour(h), minute(m), second(s) {}
friend Time add(Time t1, Time t2);
void display(){
cout << hour << " hr : " << minute << " min : " << second << " sec" << endl;
}
};

Time add(Time t1, Time t2){


int totalSec = [Link] + [Link];
int totalMin = [Link] + [Link] + totalSec / 60;
int totalHour = [Link] + [Link] + totalMin / 60;
totalSec %= 60;
totalMin %= 60;
totalHour %= 24;
return Time(totalHour, totalMin, totalSec);
}

int main(){
Time t1(5, 45, 50);
Time t2(3, 30, 20);
Time result = add(t1, t2);
cout << "Aggregate Time: ";
[Link]();
return 0;
}

7
Chapter 4: Operator Overloading
General rules for operator overloading (applies to all four below):
ˆ Only existing operators can be overloaded; new operators cannot be created.
ˆ At least one operand must be a user-defined type (class object).
ˆ Operators ::, ., .*, ?:, sizeof cannot be overloaded.
ˆ Precedence and associativity of an operator cannot be changed.
ˆ Overloading is done using the keyword operator (e.g. operator+).
ˆ Unary operators take no explicit argument (if member function); binary operators take one explicit argu-
ment (if member function) or two (if non-member/friend).

Q4 (A) – Binary Operator Overloading: 3x3 Matrix +/-

#include <iostream>
using namespace std;

class Matrix{
private:
int m[3][3];
public:
void input(){
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
cin >> m[i][j];
}
Matrix operator+(Matrix M){
Matrix temp;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
temp.m[i][j] = m[i][j] + M.m[i][j];
return temp;
}
Matrix operator-(Matrix M){
Matrix temp;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
temp.m[i][j] = m[i][j] - M.m[i][j];
return temp;
}
void display(){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)
cout << m[i][j] << " ";
cout << endl;
}
}
};

int main(){
Matrix A, B, C, D;
cout << "Enter elements of matrix A:\n"; [Link]();
cout << "Enter elements of matrix B:\n"; [Link]();
C = A + B;
D = A - B;
cout << "Sum:\n"; [Link]();
cout << "Difference:\n"; [Link]();
return 0;
}

8
Q4 (B) – Non-member Operator Overloading: Complex Numbers

#include <iostream>
using namespace std;

class Complex{
private:
float real, imag;
public:
Complex(float r=0, float i=0) : real(r), imag(i) {}
void display(){
cout << real << " + " << imag << "i" << endl;
}
friend Complex operator+(Complex, Complex);
friend Complex operator-(Complex, Complex);
friend Complex operator*(Complex, Complex);
friend Complex operator/(Complex, Complex);
};

// Syntax for overloading binary operator with non-member function:


// returnType operator OP (ClassType obj1, ClassType obj2)
Complex operator+(Complex c1, Complex c2){
return Complex([Link] + [Link], [Link] + [Link]);
}
Complex operator-(Complex c1, Complex c2){
return Complex([Link] - [Link], [Link] - [Link]);
}
Complex operator*(Complex c1, Complex c2){
float r = [Link]*[Link] - [Link]*[Link];
float i = [Link]*[Link] + [Link]*[Link];
return Complex(r, i);
}
Complex operator/(Complex c1, Complex c2){
float denom = [Link]*[Link] + [Link]*[Link];
float r = ([Link]*[Link] + [Link]*[Link]) / denom;
float i = ([Link]*[Link] - [Link]*[Link]) / denom;
return Complex(r, i);
}

int main(){
Complex c1(4, 5), c2(2, 3);
(c1+c2).display();
(c1-c2).display();
(c1*c2).display();
(c1/c2).display();
return 0;
}

Q4 (C) – Class Time with Post-increment Operator

#include <iostream>
using namespace std;

class Time{
private:
int hour, minute, second;
public:
Time(int h=0, int m=0, int s=0) : hour(h), minute(m), second(s) {}
// post-increment: dummy int parameter distinguishes from pre-increment
Time operator++(int){

9
Time temp = *this; // save old value
second++;
if(second >= 60){ second = 0; minute++; }
if(minute >= 60){ minute = 0; hour++; }
return temp;
}
void display(){
cout << hour << ":" << minute << ":" << second << endl;
}
};

int main(){
Time t1(10, 59, 59);
Time t2 = t1++; // post-increment
cout << "Before increment (t2): "; [Link]();
cout << "After increment (t1): "; [Link]();
return 0;
}

Q4 (D) – Class Length, Overload ’¿’ Operator

#include <iostream>
using namespace std;

class Length{
private:
int meter, centimeter;
public:
Length(int m, int c) : meter(m), centimeter(c) {}
int totalCm(){
return meter * 100 + centimeter;
}
bool operator>(Length L){
return (this->totalCm() > [Link]());
}
};

int main(){
Length l1(5, 40);
Length l2(4, 90);
if(l1 > l2)
cout << "Length 1 is greater" << endl;
else
cout << "Length 2 is greater or equal" << endl;
return 0;
}

Chapter 5: Inheritance
Q5 (A) – Private vs Protected; Function Overriding; Cricketer Hierarchy
Private vs Protected:
ˆ private: members are accessible only within the same class, not even by derived classes.
ˆ protected: members are accessible within the same class and by derived classes, but not from outside.

Function overriding: when a derived class defines a function with the same name and signature as one in
its base class, the derived class’s version is called for derived class objects (redefinition of base behavior).

10
#include <iostream>
#include <string>
using namespace std;

class Cricketer{
protected:
string name;
int age, matches;
public:
Cricketer(string n, int a, int m) : name(n), age(a), matches(m) {}
void display(){
cout << "Name: " << name << ", Age: " << age << ", Matches: " << matches << endl;
}
};

// Single inheritance (each derived class inherits from one base)


class Bowler : public Cricketer{
private:
int wickets;
public:
Bowler(string n, int a, int m, int w) : Cricketer(n,a,m), wickets(w) {}
void display(){ // function overriding
Cricketer::display();
cout << "Wickets: " << wickets << endl;
}
};

class Batsman : public Cricketer{


private:
int runs, centuries;
public:
Batsman(string n, int a, int m, int r, int c) : Cricketer(n,a,m), runs(r), centuries(c) {}
void display(){ // function overriding
Cricketer::display();
cout << "Runs: " << runs << ", Centuries: " << centuries << endl;
}
};

int main(){
Bowler b("Bumrah", 30, 100, 150);
Batsman s("Kohli", 35, 250, 12000, 45);
[Link]();
[Link]();
return 0;
}

Type of inheritance: Single inheritance (used twice – Bowler and Batsman each derive singly from Cricketer).

Q5 (B) – Forms of Inheritance; Person/Student with Overriding


Forms of inheritance:
ˆ Single inheritance – one derived class from one base class.
ˆ Multiple inheritance – one derived class from two or more base classes.
ˆ Multilevel inheritance – a class derived from a class which is itself derived from another (chain).
ˆ Hierarchical inheritance – multiple derived classes from a single base class.
ˆ Hybrid inheritance – combination of two or more forms above.

#include <iostream>
#include <string>

11
using namespace std;

class Person{
protected:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
void display(){
cout << "Name: " << name << ", Age: " << age << endl;
}
};

class Student : public Person{ // single inheritance


private:
string course;
public:
Student(string n, int a, string c) : Person(n,a), course(c) {}
void display(){ // overriding
Person::display();
cout << "Course: " << course << endl;
}
};

int main(){
Student s("Mohan", 21, "Computer Engineering");
[Link]();
return 0;
}

Q5 (C) – Inheritance Definition; Overriding vs Overloading; Multilevel Constructor Order


Inheritance: the mechanism by which a new class (derived/child class) acquires the properties (data members)
and behaviors (member functions) of an existing class (base/parent class), promoting code reuse.
Overriding vs Overloading:
ˆ Overloading – same function name, different parameter lists, within the same class (compile-time/static
polymorphism).
ˆ Overriding – same function name and signature, redefined in a derived class (run-time polymorphism
when used with virtual functions).

#include <iostream>
using namespace std;

class A{
public:
A(){ cout << "Constructor of A called" << endl; }
};
class B : public A{
public:
B(){ cout << "Constructor of B called" << endl; }
};
class C : public B{
public:
C(){ cout << "Constructor of C called" << endl; }
};

int main(){
C obj; // constructors are called in order: A -> B -> C
return 0;

12
}

Output order: A’s constructor, then B’s, then C’s – base class constructors always run before the derived class
constructor, starting from the topmost base.

Q5 (D) – IS-A / HAS-A; Multipath Inheritance & Ambiguity


IS-A relation: represents inheritance – a derived class is a type of the base class (e.g., Dog IS-A Animal).
Implemented via class Dog : public Animal.
HAS-A relation: represents composition/containment – a class has a member object of another class (e.g.,
Car HAS-A Engine). Implemented by including an object of one class as a data member of another.
Multipath inheritance: occurs when a derived class inherits from two base classes that both derive
from a common base class – the common base class’s members end up being inherited via two paths, causing
duplication.
Resolving ambiguity: Use the virtual base class mechanism – declare the common base class as virtual
in both intermediate classes (class B : virtual public A, class C : virtual public A), ensuring only
one copy of A’s members exists in the final derived class D.
#include <iostream>
using namespace std;

class A{
public:
int x = 10;
};
class B : virtual public A{};
class C : virtual public A{};
class D : public B, public C{};

int main(){
D d;
cout << d.x << endl; // no ambiguity due to virtual inheritance
return 0;
}

Chapter 6: Virtual Functions


Q6 (A) – Virtual Destructor; Overloading vs Overriding
Need for virtual destructor: If a base class pointer pointing to a derived class object is deleted and the base
class destructor is not virtual, only the base class destructor is called – the derived class’s destructor (and its
cleanup, e.g. freeing dynamically allocated memory) is skipped, causing a memory leak. Declaring the base
destructor virtual ensures the derived class destructor is called too.
#include <iostream>
using namespace std;

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

int main(){
Base *b = new Derived();
delete b; // both destructors called because ~Base() is virtual
return 0;

13
}

Overloading vs overriding: see Chapter 5, Q5(C).

Q6 (B) – Early vs Late Binding; Employee/Manager with Virtual Function


Early binding (static binding): function call is resolved at compile time (e.g., normal function calls, over-
loaded functions). Faster but less flexible.
Late binding (dynamic binding): function call is resolved at run time based on the actual object type,
achieved using virtual functions and base class pointers/references. Enables run-time polymorphism.
#include <iostream>
#include <string>
using namespace std;

class Employee{
protected:
string name;
float salary;
public:
Employee(string n, float s) : name(n), salary(s) {}
virtual void display(){
cout << "Employee: " << name << ", Salary: " << salary << endl;
}
virtual ~Employee() {}
};

class Manager : public Employee{


private:
string department;
public:
Manager(string n, float s, string d) : Employee(n,s), department(d) {}
void display() override{ // virtual function -> late binding
cout << "Manager: " << name << ", Salary: " << salary
<< ", Dept: " << department << endl;
}
};

int main(){
Employee *e = new Manager("Sita", 80000, "IT");
e->display(); // calls Manager::display() at run time (late binding)
delete e;
return 0;
}

Q6 (C) – Virtual Function; Pure Virtual Function


Virtual function: a member function declared in a base class using the keyword virtual, which can be
redefined (overridden) in a derived class. When accessed through a base class pointer/reference, the derived
class’s version is invoked at run time (late binding).
Pure virtual function: a virtual function with no body/definition in the base class, declared by assigning
= 0. It forces every derived class to provide its own implementation. A class containing at least one pure virtual
function becomes an abstract class and cannot be instantiated directly.
#include <iostream>
using namespace std;

class Shape{
public:
virtual float area() = 0; // pure virtual function -> abstract class
};

14
class Circle : public Shape{
private:
float radius;
public:
Circle(float r) : radius(r) {}
float area() override{
return 3.14 * radius * radius;
}
};

int main(){
Shape *s = new Circle(5);
cout << "Area: " << s->area() << endl;
delete s;
return 0;
}

Q6 (D) – Abstract Class; Employee/Student -¿ Manager/Secretary with Virtual Destructor


Abstract class: a class that contains at least one pure virtual function. It cannot be used to create objects
directly; it serves as a base class that defines an interface which derived classes must implement.
#include <iostream>
#include <string>
using namespace std;

class Employee{
protected:
string name;
public:
Employee(string n) : name(n) {}
virtual void display(){
cout << "Employee Name: " << name << endl;
}
virtual ~Employee(){ cout << "~Employee" << endl; }
};

class Student{
protected:
string roll;
public:
Student(string r) : roll(r) {}
virtual ~Student(){ cout << "~Student" << endl; }
};

// Multiple inheritance: Manager derived from Employee and Student


class Manager : public Employee, public Student{
public:
Manager(string n, string r) : Employee(n), Student(r) {}
void display() override{
Employee::display();
cout << "Roll: " << roll << endl;
}
~Manager(){ cout << "~Manager" << endl; }
};

// Single inheritance: Secretary derived from Employee


class Secretary : public Employee{
public:

15
Secretary(string n) : Employee(n) {}
~Secretary(){ cout << "~Secretary" << endl; }
};

int main(){
Employee *e1 = new Manager("Ram", "21001");
e1->display();
delete e1; // virtual destructor ensures ~Manager, ~Student, ~Employee all run

Employee *e2 = new Secretary("Sita");


e2->display();
delete e2; // virtual destructor ensures ~Secretary, ~Employee run

return 0;
}

Chapter 7: Stream Computation (File I/O)


Q7 (A) – I/O Error Handling; Read/Write/Copy with Case Conversion
Handling abnormal situations in I/O: The stream classes maintain internal state flags – eofbit (end of
file reached), failbit (operation failed, e.g. wrong data type), badbit (irrecoverable error), and goodbit (no
error). Functions eof(), fail(), bad(), and good() check these flags so the program can detect and handle
errors (e.g., file not opening, or attempting to read past end of file) gracefully instead of crashing.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(){
ofstream outFile("[Link]");
if(!outFile){ cout << "Error creating file" << endl; return 1; }

string text;
cout << "Enter text to write to source file: ";
getline(cin, text);
outFile << text;
[Link]();

// Read from source, convert lowercase->uppercase, write to destination


ifstream inFile("[Link]");
ofstream destFile("[Link]");
char ch;
while([Link](ch)){
if(ch >= ’a’ && ch <= ’z’)
ch = ch - ’a’ + ’A’;
[Link](ch);
}
[Link]();
[Link]();

// Display content of destination file


ifstream readDest("[Link]");
if([Link]()){
cout << "Error opening destination file" << endl;
return 1;
}
cout << "Destination file content:\n";
while([Link](ch))

16
cout << ch;
cout << endl;
[Link]();
return 0;
}

Q7 (B) – File Modes; Employee Records with Search by ID


File modes in C++ (<fstream>):
ˆ ios::in – open for reading.
ˆ ios::out – open for writing.
ˆ ios::app – append to end of file.
ˆ ios::ate – open and seek to end of file.
ˆ ios::trunc – truncate (delete existing content) if file exists.
ˆ ios::binary – open in binary mode.

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Employee{
public:
string name;
int id;
int age;
float salary;

void getData(){
cout << "Enter name, id, age, salary: ";
cin >> name >> id >> age >> salary;
}
void showData(){
cout << name << "\t" << id << "\t" << age << "\t" << salary << endl;
}
};

int main(){
Employee e;
fstream file("[Link]", ios::out | ios::binary | ios::trunc);
for(int i = 0; i < 10; i++){
[Link]();
[Link]((char*)&e, sizeof(e));
}
[Link]();

// Display all records


[Link]("[Link]", ios::in | ios::binary);
cout << "\nAll Employee Records:\n";
while([Link]((char*)&e, sizeof(e)))
[Link]();
[Link]();

// Search by employee ID
int searchId;
cout << "\nEnter employee ID to search: ";
cin >> searchId;
[Link]("[Link]", ios::in | ios::binary);
bool found = false;

17
while([Link]((char*)&e, sizeof(e))){
if([Link] == searchId){
cout << "Record found:\n";
[Link]();
found = true;
break;
}
}
if(!found) cout << "Record not found." << endl;
[Link]();
return 0;
}

Q7 (C) – Random Access; Student Records with Search by Roll No


Random access of data in file: Normally, file streams read/write sequentially. Random access allows jumping
directly to any position using:
ˆ seekg(offset, ref) / seekp(offset, ref) – move the get/put pointer to a byte offset from ios::beg,
ios::cur, or ios::end.
ˆ tellg() / tellp() – return the current position.
For fixed-size records (using read/write with binary mode), the position of record n is n × sizeof(record),
allowing direct access without reading preceding records.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Student{
public:
int roll;
string name, address;
int batch;

void getData(){
cout << "Enter roll, name, address, batch: ";
cin >> roll >> name >> address >> batch;
}
void showData(){
cout << roll << "\t" << name << "\t" << address << "\t" << batch << endl;
}
};

int main(){
int n;
Student s;
cout << "Enter number of students: ";
cin >> n;

fstream file("[Link]", ios::out | ios::binary | ios::trunc);


for(int i = 0; i < n; i++){
[Link]();
[Link]((char*)&s, sizeof(s));
}
[Link]();

// Random access search by roll number


int searchRoll;
cout << "Enter roll number to search: ";

18
cin >> searchRoll;

[Link]("[Link]", ios::in | ios::binary);


bool found = false;
for(int i = 0; i < n; i++){
[Link](i * sizeof(s), ios::beg); // jump directly to record i
[Link]((char*)&s, sizeof(s));
if([Link] == searchRoll){
cout << "Record found:\n";
[Link]();
found = true;
break;
}
}
if(!found) cout << "Student not found." << endl;
[Link]();
return 0;
}

Q7 (D) – File Access Types; Library Records


Types of file access:
ˆ Sequential access – data read/written in order from beginning to end (default).
ˆ Random access – data accessed directly at any position using seekg/seekp (see Q7(C)).

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Book{
public:
int bookId;
string title, author;

void getData(){
cout << "Enter book ID, title, author: ";
cin >> bookId >> title >> author;
}
void showData(){
cout << bookId << "\t" << title << "\t" << author << endl;
}
};

int main(){
Book b;
ofstream outFile("[Link]", ios::binary);
cout << "Enter details of 5 books:\n";
for(int i = 0; i < 5; i++){
[Link]();
[Link]((char*)&b, sizeof(b));
}
[Link]();

ifstream inFile("[Link]", ios::binary);


cout << "\nLibrary Records:\n";
while([Link]((char*)&b, sizeof(b)))
[Link]();
[Link]();

19
return 0;
}

Chapter 8: Templates
Q8 (A) – Templates as Generic Programming; STL Containers/Iterators; Default Args in Class
Template
Templates as generic programming: Templates let a single function or class definition work with multiple
data types – the compiler generates a specific version for each type used, at compile time. This avoids writing
separate code for int, float, etc., embodying ”generic programming.”
STL Containers: data structures that store collections of objects, e.g. vector, list, map, set, stack,
queue.
STL Iterators: objects that point to elements of a container and allow traversal (like generalized pointers),
e.g. begin(), end().
#include <iostream>
using namespace std;

// Class template with a default type argument


template <class T = int>
class Box{
private:
T value;
public:
Box(T v) : value(v) {}
void display(){ cout << "Value: " << value << endl; }
};

int main(){
Box<int> b1(10); // explicit type
Box<> b2(5); // uses default type (int)
Box<double> b3(3.14); // double type
[Link]();
[Link]();
[Link]();
return 0;
}

Q8 (B) – Code Redundancy via Templates; Sort n Numbers (Descending) using vector
Eliminating redundancy: Without templates, separate sort functions would be needed for int, float, etc.
A single function template works for any type.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

template <class T>


void sortDescending(vector<T> &v){
sort([Link](), [Link](), greater<T>());
}

template <class T>


void display(vector<T> &v){
for(auto x : v) cout << x << " ";
cout << endl;
}

20
int main(){
int n;
cout << "Enter number of elements: ";
cin >> n;
vector<float> nums(n);
cout << "Enter " << n << " numbers: ";
for(int i = 0; i < n; i++) cin >> nums[i];

sortDescending(nums); // template function works for any data type


cout << "Sorted (descending): ";
display(nums);
return 0;
}

Q8 (C) – Justify: Templates Enable Generic Programming


This statement is justified because a single template definition automatically generates type-specific code for
each data type it is used with, eliminating the need to rewrite the same logic repeatedly.
#include <iostream>
using namespace std;

// Function template -- works for int, float, char, etc.


template <class T>
T findMax(T a, T b){
return (a > b) ? a : b;
}

// Class template -- works for any data type


template <class T>
class Pair{
private:
T first, second;
public:
Pair(T f, T s) : first(f), second(s) {}
T getMax(){ return findMax(first, second); }
};

int main(){
cout << "Max int: " << findMax(10, 20) << endl;
cout << "Max double: " << findMax(3.5, 2.1) << endl;

Pair<int> p1(15, 30);


Pair<char> p2(’a’, ’z’);
cout << "Pair1 max: " << [Link]() << endl;
cout << "Pair2 max: " << [Link]() << endl;
return 0;
}

This single findMax and Pair definition serves int, double, char (and any type supporting >) – demonstrating
reusable, type-independent code as claimed.

Q8 (D) – Default Argument in Template Class; Function Template; Stack in STL

#include <iostream>
using namespace std;

// Class template with a default argument value for constructor


template <class T>

21
class Item{
private:
T value;
public:
Item(T v = T()) : value(v) {} // default argument
void display(){ cout << "Value: " << value << endl; }
};

// Function template
template <class T>
T multiply(T a, T b){
return a * b;
}

int main(){
Item<int> i1; // uses default argument (0)
Item<int> i2(25);
[Link]();
[Link]();

cout << "Product (int): " << multiply(4, 5) << endl;


cout << "Product (double): " << multiply(2.5, 4.0) << endl;
return 0;
}

Stack in STL: stack is a container adapter that provides LIFO (Last-In-First-Out) access. Defined in
<stack>, common operations: push() (insert at top), pop() (remove top), top() (access top element), empty(),
size(). Example: stack<int> s; [Link](10); [Link]();

Chapter 9: Exception Handling


Q9 (A) – Exception Handling Advantage; Multiple Exceptions for Roll No & Marks
How exception handling is better than traditional error handling: Traditionally, error codes returned
by functions must be checked manually after every call, mixing error-handling code with normal logic and often
being ignored. Exception handling separates error-detection (throw) from error-handling (catch) code using
try blocks, allows propagation of errors up the call stack automatically, and supports handling multiple/different
error types distinctly via multiple catch blocks – making code cleaner and more robust.
#include <iostream>
#include <string>
using namespace std;

class InvalidRoll{
public:
int roll;
InvalidRoll(int r) : roll(r) {}
};
class InvalidMarks{
public:
float marks;
InvalidMarks(float m) : marks(m) {}
};

int main(){
string name;
int roll;
float marks, fullMarks = 100;

cout << "Enter name, roll number, marks: ";

22
cin >> name >> roll >> marks;

try{
if(roll < 0)
throw InvalidRoll(roll);
if(marks > fullMarks)
throw InvalidMarks(marks);

cout << "Valid record:\n";


cout << "Name: " << name << ", Roll: " << roll << ", Marks: " << marks << endl;
}
catch(InvalidRoll &e){
cout << "Error: Roll number cannot be negative (" << [Link] << ")" << endl;
}
catch(InvalidMarks &e){
cout << "Error: Marks (" << [Link] << ") exceed full marks (" << fullMarks << ")" << endl;
}
return 0;
}

Q9 (B) – Exception Handling Constructs; Multiple Scenarios


Constructs:
ˆ try block – encloses code that might raise an exception.
ˆ throw – used to signal (raise) an exception, optionally with a value/object.
ˆ catch block – catches and handles a thrown exception of a matching type.

#include <iostream>
using namespace std;

int main(){
int a, b;
cout << "Enter two numbers: ";
cin >> a >> b;

try{
if(b == 0)
throw runtime_error("Division by zero!");
if(a < 0 || b < 0)
throw -1; // throwing an int

cout << "Result: " << a / b << endl;


}
catch(runtime_error &e){
cout << "Runtime error: " << [Link]() << endl;
}
catch(int code){
cout << "Error code " << code << ": Negative numbers not allowed." << endl;
}
catch(...){
cout << "Unknown exception occurred." << endl;
}
return 0;
}

Q9 (C) – What are Exceptions; Program with Multiple Exceptions


Exception: a runtime anomaly or unexpected condition (e.g., division by zero, invalid input, out-of-range
access) that disrupts the normal flow of a program. C++ provides a structured mechanism (try/throw/catch)

23
to detect and respond to such conditions without crashing the program.
#include <iostream>
using namespace std;

int main(){
int arr[5] = {1,2,3,4,5};
int index;
cout << "Enter index to access (0-4): ";
cin >> index;

try{
if(index < 0 || index >= 5)
throw out_of_range("Index out of bounds");
cout << "Value: " << arr[index] << endl;

int divisor;
cout << "Enter a divisor: ";
cin >> divisor;
if(divisor == 0)
throw runtime_error("Cannot divide by zero");
cout << "100 / divisor = " << 100/divisor << endl;
}
catch(out_of_range &e){
cout << "Error: " << [Link]() << endl;
}
catch(runtime_error &e){
cout << "Error: " << [Link]() << endl;
}
return 0;
}

Q9 (D) – Steps in Exception Handling; Square Root Program


Steps in exception handling:
1. Place the risky code inside a try block.
2. If an error condition occurs, use throw to raise an exception (with an object/value describing the error).
3. Control transfers immediately out of the try block to a matching catch block (skipping remaining code
in try).
4. The catch block handles the exception (e.g., displays an error message).
5. If no catch matches, the exception propagates up the call stack; if unhandled, the program terminates
via terminate().

#include <iostream>
#include <cmath>
using namespace std;

int main(){
double num;
cout << "Enter a number: ";
cin >> num;

try{
if(num < 0)
throw invalid_argument("Cannot compute square root of a negative number");
cout << "Square root = " << sqrt(num) << endl;
}
catch(invalid_argument &e){
cout << "Error: " << [Link]() << endl;

24
}
return 0;
}

25

You might also like