OOP Spring 25 Final - Solution
OOP Spring 25 Final - Solution
int main() {
Complex c1(3.2,
4.5), c2(1.1, 2.2);
Complex c3 = c1 +
c2;
c3.display();
return 0;
}
and also const
Complex& c:
Improves efficiency
by avoiding
unnecessary
copying.
3.class A{ Solution
int x; #include <iostream>
public: A(int i) { x = i; } using namespace std;
void show() { cout << x; } class A {
int x;
};
public:
class B: virtual public A{
A(int i) { x = i; }
public: B(int i):A(i) { } void show() { cout
}; << x; }
class C: virtual public A{ };
public: C(int i):B(i) { } class B : virtual public
}; A{
class D: public B, public C { public:
}; B(int i) : A(i) { }
int main(){ };
D d(5); class C : virtual public
d.show(); A{
public:
return 0;
C(int i) : A(i) { }
}
};
class D : public B,
public C {
public:
D(int i) : A(i), B(i),
C(i) { }
};
int main() {
D d(5);
d.show();
return 0;
}
4. #include <iostream> Solution
#include <string> #include <iostream>
using namespace std; #include <string>
using namespace std;
class DivisionError {
class DivisionError {
string msg;
string msg;
public:
}; DivisionError(string
m) : msg(m) {}
class Calculator { void
public: showMessage()
static double divide(int a, int b) { const {
if (b == 0) cout << "Division
throw DivisionError("Cannot divide by Error: " << msg <<
zero"); endl;
if (a < 0 || b < 0) }
};
throw "Negative input not allowed";
class Calculator {
return static_cast<double>(a) / b;
public:
} static double
divide(int a, int b) {
static void compute() { if (b == 0)
try { throw
cout << "Result: " << divide(10, 2) << DivisionError("Cann
endl; ot divide by zero");
cout << "Result: " << divide(-5, 1) << if (a < 0 || b < 0)
endl; // Will throw: string throw
cout << "Result: " << divide(8, 0) << endl; "Negative input not
// Won't be reached allowed";
} return
catch (const DivisionError& e) { static_cast<double>
(a) / b;
e.showMessage();
}
try {
static void compute()
cout << "Retrying...\n"; {
divide(6, 0); // Throws again try {
} cout << "Result:
catch (const DivisionError& ex) { " << divide(10, 2) <<
ex.showMessage(); endl;
} cout << "Result:
} " << divide(-5, 1) <<
catch (const char* msg) { endl; // Will throw:
string
cout << "Caught string exception: " << cout << "Result: " <<
msg << endl; divide(8, 0) << endl;
try { // Won't be reached
cout << "Trying a safe division...\n"; }
cout << "Result: " << divide(8, 2) << catch (const
endl; // Safe call DivisionError& e) {
}
e.showMessage();
catch (...) {
try {
cout << "Unexpected exception during cout <<
safe retry\n"; "Retrying...\n";
} divide(6, 0);
} // Throws again
catch (...) { }
cout << "Unknown error occurred!" << catch (const
endl; DivisionError& ex) {
}
} ex.showMessage();}
}; }
catch (const char*
msg) {
int main() {
cout << "Caught
Calculator::compute(); string exception: "
return 0; << msg << endl;
} try {
cout <<
"Trying a safe
division...\n";
cout <<
"Result: " <<
divide(8, 2) << endl;
// Safe call
}
catch (...) {
cout << "Unexpected
exception during
safe retry\n"; } }
catch (...) {
cout <<
"Unknown error
occurred!";}
}};
int main() {
Calculator::compute
();
return 0;
}
Karachi Ca mpus
Q1:Part B: Find the output of the codes given. There are no syntax errors.
1. class SecureVault { 2. class Universe 3. class Core {
int secretKey; { static int count; public:
string password; int id; Core() { cout << "Core()" << endl; }
public: public: virtual ~Core() { cout << "~Core()" <<
SecureVault(int key, string Universe() : id(++count) { cout << endl; }
pwd) : secretKey(key), "Universe #" << id << " created." << virtual void execute() = 0;};
password(pwd){} endl; } class PluginA : virtual public Core
friend class Hacker; ~Universe() { cout << "Universe #" { public:
void reveal() const { cout << << id << " destroyed." << endl; } PluginA() { cout << "PluginA()" << endl; }
"Key: " << secretKey << " | static void reset() { count = 0; } void execute() override { cout <<
Password: " << password << }; "PluginA::execute()" << endl; }};
endl; }}; int Universe::count = 0; class PluginB : virtual public Core {
class Hacker { int main() { public:
public: Universe::reset(); PluginB() { cout << "PluginB()" << endl; }
void crack(SecureVault& vault) Universe u1, u2; void execute() override { cout <<
{ { "PluginB::execute()" << endl; }};
vault.secretKey = 999; Universe u3; class Hybrid : public PluginA, public PluginB {
cout << "Cracked: " << } public:
vault.password << endl;}}; Universe* u4 = new Universe(); Hybrid() { cout << "Hybrid()" << endl; }
int main() { delete u4; void execute() override {
SecureVault vault(42, return 0; cout << "Hybrid::execute()" << endl;
"Admin@123"); } PluginA::execute();
Hacker evil; PluginB::execute(); }};
Universe #1 created.
evil.crack(vault); int main() {
vault.reveal(); Universe #2 created. Core* system = new Hybrid();
return 0;} Universe #3 created. system->execute();
Cracked: Admin@123 delete system; return 0;}
Universe #3 destroyed.
Key: 999 | Password: Core()
Universe #4 created.
Admin@123 PluginA()
Universe #4 destroyed.
PluginB()
Universe #2 destroyed.
Hybrid()
Universe #1 destroyed.
Hybrid::execute()
PluginA::execute()
PluginB::execute()
~Core()
Q1:Part C: Complete the missing codes based on the code snippets and outputs provided. Assume there is no
mistake in the code provided and required libraries are included.
1. int myFunction(int value){ 2. /* */ 3. template<typename T>
if (value == 0) int main() { bool greaterThan(T val1, T val2) {
return 0; string fileName[2] = { if (val1 > val2)
else if (value == 10) "input.txt", "output.txt" }; return true;
return 1; else
else writeStringToFile(fileName[1], return false;}
throw 100; readStringFromFile(fileName[0] /*
} )); */ int main() {
int main() { int i1 = 10, i2 = 20;
int num1 = 0, num2 = 10, return 0; float f1 = 10.1f, f2 = 20.2f;
num3 = 100; } Q4 obj1(10), obj2(20);
int res1, res2, res3;
/* */ Solution cout << greaterThan(i1, i2) << ",
Solution " << greaterThan(i2, i1) << endl;
string readStringFromFile(string cout << greaterThan(f1, f2) <<
fileName) { ", " << greaterThan(f2, f1) << endl;
try { fstream fin(fileName, ios::in); cout << greaterThan(obj1, obj2)
string str; << ", " << greaterThan(obj2, obj1) <<
res1 = myFunction(num1); getline(fin, str); endl;
return str; return 0;}
res2 = myFunction(num2); } Solution
void writeStringToFile(string fileName,
string data) { class Q4 {
res3 = myFunction(num3);
fstream fout(fileName, int q4;
ios::out);
} string str = data + " " + data; public:
fout << str; Q4 (int a) {
catch (int i) { } q4 = a;
}.
cout << i << endl; bool operator > (Q4& obj) {
if (this->q4 > obj.q4)
cout << res1 << ", " << return true;
res2 << endl; else
return false;
} }
};
CLO 4: Illustrate Object-Oriented design artifacts and their mapping to Object-Oriented Programming using C++. [Marks 10, 45 min]
Q2: In the heat of the 2025 Indo-Pak digital conflict, Pakistan's elite cyber unit—Unit Zero-Hawk—launches a top-
secret cyber offensive, code-named Operation Bunyan-ul-Marsoos. The operation involves breaching India’s
encrypted cyber defense system and deploying stealth payloads through a C++-driven terminal simulation.
Phase 1: Mission Setup – Abstract Class Design (1 mark)
Define an abstract class CyberOperation containing the following pure virtual functions:
● accessIntel() – Reads data from the binary file, decrypts payloads using Caesar cipher from Phase 3, and
displays only undeleted records.
● extractPayload() – Extracts records with high risk level (≥ 8) based on riskLevel logic from Phase 2 and
saves them into a separate file as described in Phase 4.
● deleteTraces() – Marks high-risk records as deleted using logic from Phase 5.
Implement these pure virtual functions in a derived class (e.g., Operation).If necessary, declare friend class Operation;
in the IntelRecord class to permit file-level data access OR add public getters/setters if needed.
Phase 2: Data Infiltration – Binary File Creation (3 marks)
Create a class IntelRecord with the following attributes: int recordID, char targetLocation[50], int riskLevel, char
payload[100], bool isDeleted. Implement the following functions:
● input() – Takes user input for all fields and encrypts the payload using Caesar cipher with a shift of +3.
● display(bool decrypt) – Displays record details; if decrypt is true, decrypts the payload using Caesar cipher
(relevant for Phase 3).
● getRiskLevel() – Returns the risk level of the record; used in Phase 4 and Phase 5.
● isMarkedDeleted() – Returns true if the record is already marked as deleted; used in Phase 3.
● markDeleted() – Sets the deletion status to true; used in Phase 5.
Phase 3: Accessing Classified Data (2 marks)
Open intel.dat in binary mode, read all records, and display only those where isDeleted is false. Each displayed record
must have its payload decrypted using Caesar cipher with a shift of -3.
Caesar Cipher (Explanation):It shifts each character by a fixed number of positions.
Example: Original text = attack, shift +3 → dwwdfn To decrypt, shift -3 → dwwdfn → attack
Phase 4: High-Risk Extraction (1 mark)
Find all records with riskLevel >= 8 (as defined in Phase 2) and copy them into a file named extracted.dat.
If no such record exists, throw ExtractionException.
Phase 5: Digital Sanitization (1 mark)
Open intel.dat and mark all records with riskLevel >= 8 (refer to Phase 2) as deleted using markDeleted().
If no records are updated, throw DeleteTraceException.
Phase 6: Exception Handling War Room (2 marks) Define the following custom exceptions:
● FileAccessException – Thrown when a file fails to open("File could not be opened!").
● ExtractionException – Thrown when no high-risk data is found during extraction ("No high-risk records found
for extraction!")(used in Phase 4).
● DeleteTraceException – Thrown when no records are marked as deleted (used in Phase 5).( "No traces
marked as deleted!")
Solution
#include <iostream>
#include <fstream>
class DeleteTraceException {
public:
const char* what() const {
return "No traces marked as deleted!";
}
};
public:
IntelRecord() {
isDeleted = false;
}
void input() {
cout << "Enter Record ID: ";
cin >> recordID;
cin.ignore();
cout << "Enter Target Location: ";
cin.getline(targetLocation, 50);
cout << "Enter Risk Level (1-10): ";
cin >> riskLevel;
cin.ignore();
cout << "Enter Payload: ";
cin.getline(payload, 100);
isDeleted = false;
}
void display(bool decrypt = false) {
cout << "\nRecord ID: " << recordID;
cout << "\nTarget Location: " << targetLocation;
cout << "\nRisk Level: " << riskLevel;
cout << "\nPayload: ";
if (decrypt) {
for (int i = 0; payload[i] != '\0'; i++) {
cout << char(payload[i] - 3);
}
} else {
cout << payload;
}
cout << "\nDeleted: " << (isDeleted ? "Yes" : "No") << endl;
}
int getRiskLevel() {
return riskLevel;
}
bool isMarkedDeleted() {
return isDeleted;
}
void markDeleted() {
isDeleted = true;
}
};
IntelRecord rec;
rec.input();
outFile.write((char*)&rec, sizeof(rec));
outFile.close();
}
void accessIntel() {
ifstream inFile("intel.dat", ios::binary);
if (!inFile) throw FileAccessException();
IntelRecord rec;
cout << "\n--- Accessing Classified Data ---\n";
while (inFile.read((char*)&rec, sizeof(rec))) {
if (!rec.isMarkedDeleted()) {
rec.display(true); // decrypt = true
}
}
inFile.close();
}
void extractPayload() {
ifstream inFile("intel.dat", ios::binary);
ofstream outFile("extracted.dat", ios::binary);
IntelRecord rec;
bool found = false;
inFile.close();
outFile.close();
void deleteTraces() {
fstream file("intel.dat", ios::binary | ios::in | ios::out);
if (!file) throw FileAccessException();
IntelRecord rec;
bool deleted = false;
streampos pos;
file.close();
// Main Simulation
int main() {
Operation op;
int choice;
while (true) {
cout << "\n=== Operation Banayn-ul-Masroor ===";
cout << "\n1. Add Intel Record";
cout << "\n2. Access Classified Data";
cout << "\n3. Extract High-Risk Payloads";
cout << "\n4. Sanitize Digital Traces";
cout << "\n5. Exit";
cout << "\nEnter choice: ";
cin >> choice;
try {
switch (choice) {
case 1:
op.writeIntelToFile();
break;
case 2:
op.accessIntel();
break;
case 3:
op.extractPayload();
break;
case 4:
op.deleteTraces();
break;
case 5:
cout << "\n\"In the end, it wasn't the bullet that mattered—it was the byte.\"";
cout << "\n— Unit Zero-Hawk, Post-Mission Debrief\n";
return 0;
default:
cout << "Invalid choice!";
}
} catch (FileAccessException& e) {
cout << "Error: " << e.what() << endl;
} catch (ExtractionException& e) {
cout << "Error: " << e.what() << endl;
} catch (DeleteTraceException& e) {
cout << "Error: " << e.what() << endl;
}
}
return 0;
}
CLO 4: Illustrate Object-Oriented design artifacts and their mapping to Object-Oriented Programming using C++. [Marks 5, 30 min]
Q3: E-Shop is an online retail platform that allows customers to purchase a variety of products from different
vendors. You are required to design the system using the object oriented principles learned.
Customer Class: [1.5 marks]
● Attributes: Attributes: id(int), name(string), Array of Shopping cart (shows products in the cart).Create a
Parameterized constructor and a destructor.
● searchProducts(Product *p, product name): searches for a specific product in the list of products. If it’s
available, display the product or else display “not available”.
Product Class: [1 mark]
● Attributes: id(int), name(string), description(string), quantity(int), price(double). Create a Parameterized
constructor and a destructor.
Shopping Cart Class: [2.5 marks]
● Attributes: Array of Products (stores products that are currently in the cart)
● 1. void addItem(Product& product, int quantity): adds items if the array is not full and product does not
exceed or is in negative quantity.
● 2. double getTotal(): calculates the total bill for the products in the cart.
CLO 5: Synthesize programs using Generic Programming and exception handling [Marks 10, 45 min]
Solution
class Product;
// ShoppingCart Class
class ShoppingCart {
private:
Product* products;
int capacity;
int productCount;
public:
ShoppingCart(int capacity) : capacity(capacity), productCount(0) {
products = new Product[capacity]; /
}
~ShoppingCart() {
delete[] products;
}
cout << quantity << " " << product.name << "(s) added to cart." << endl;
} else if (productCount >= capacity) {
cout << "Cart is full. Cannot add more items." << endl;
} else if (quantity <= 0) {
cout << "Invalid quantity. Please enter a positive number." << endl;
}
else {
cout << "Insufficient stock of " << product.name << ". Available quantity: " << product.quantity << endl;
}
}
// Function to calculate the total bill for the products in the cart
double getTotal() const {
double total = 0.0;
for (int i = 0; i < productCount; ++i) {
total += products[i].price * products[i].quantity;
}
return total;
}
// Product Class
class Product {
public:
int id;
string name;
string description;
int quantity;
double price;
Product(int id, const string& name, const string& description, int quantity, double price)
: id(id), name(name), description(description), quantity(
~Product() {} quantity), price(price) {}
};
// Customer Class
class Customer {
private:
int id;
string name;
ShoppingCart cart; // Object of ShoppingCart class
public:
Customer(int id, const string& name, int cartCapacity) : id(id), name(name), cart(cartCapacity) {}
~Customer() {}
void searchProducts(Product* products, int numProducts, const string& productName) const {
bool found = false;
for (int i = 0; i < numProducts; ++i) {
if (products[i].name == productName) {
cout << "Product found:" << endl;
cout << "ID: " << products[i].id << ", Name: " << products[i].name
<< ", Description: " << products[i].description << ", Quantity: "
<< products[i].quantity << ", Price: $" << fixed << setprecision(2) << products[i].price << endl;
found = tr0ue;
break; // Exit the loop since the product is found
}
}
if (!found) {
cout << "Product \"" << productName << "\" not available." << endl;
}
}
Q4: Implement a generic ImagePixelCalculator class that performs various image processing operations on generic 2D
image matrices. These matrices can hold pixel values in types such as Integer, Float, or Double. Each generic image
matrix is represented as a 2D array, where each element represents the pixel value of that image at a specific
position.
● The generic class should be named ImagePixelCalculator.The class should have two generic attributes, image1
and image2, which store the pixel values of two images. These generic matrices are of any type (supporting
Integer, Float, Double, and other numeric types). The generic matrices should be 2D arrays of the same size,
meaning both matrices must have the same number of rows and columns.(1 Mark)
● The class should have a constructor that initializes the image1 and image2 generic matrices. The
constructor should ensure that both generic matrices have the same dimensions (rows and columns). If
the dimensions of the matrices do not match, an IllegalArgumentException should be thrown.(2 Marks)
● The class should include getter and setter methods for the image1 and image2 attributes to allow access to
and modification of the generic 2D matrices. The getter methods should return the generic matrices, and the
setter methods should allow the matrices to be set to new values. (1 Mark)
● The class should include several generic methods to perform classical image processing operations on the
two image matrices: All methods for image processing (denormalizeImage, normalizeImage, applyFilter,
smoothImage, transposeImage) have been updated to take two generic 2D image matrices as parameters.
The methods perform operations on these matrices of all the types mentioned above.
● denormalizeImage(): This method should perform pixel-wise addition of corresponding values from image1
and image2 and return the result as a generic 2D matrix of any type . (1 Mark)
normalizeImage(): This method should perform pixel-wise subtraction of corresponding values from image1
and image2 and return the result as a 2D matrix of any type( 1 Marks)
applyFilter(): This method should perform pixel-wise multiplication of corresponding values from image1
and image2 and return the result as a 2D matrix of any type( 1 Mark)
smoothImage(): This method should perform pixel-wise averaging of corresponding values from image1 and
image2 and return the result as a 2D matrix of any type (1 Mark)
transposeImage(): This method should return the transpose of image2 as a 2D matrix. (1 Mark)
● printImageMatrix(): This method should be a generic method that prints any 2D matrix (of any type to the
console. It can be used to display the results of the image processing operations. images in sequence. (1
Mark)
solution
#include <iostream>
#include <iomanip>
#include <stdexcept>
using namespace std;
public:
// Constructor with dimension check
ImagePixelCalculator(T1 img1Input[ROWS][COLS], T2 img2Input[ROWS][COLS], int rows, int
cols) {
if (rows != ROWS || cols != COLS) {
throw invalid_argument("Dimension mismatch: Expected 2x2 matrices.");
}
setImage1(img1Input);
setImage2(img2Input);
}
double (*getResult())[COLS] {
return result;
}
template<typename T>
void transposeImage(T matrix[ROWS][COLS], T transposed[ROWS][COLS]) {
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
transposed[j][i] = matrix[i][j];
}
void processAndDisplay() {
cout << "Denormalized Image (Addition):" << endl;
denormalizeImage();
printMatrix(result);
int main() {
float img1[ROWS][COLS] = {
{1.5f, 2.5f},
{3.5f, 4.5f}
};
double img2[ROWS][COLS] = {
{0.5, 1.0},
{1.5, 2.0}
};
try {
ImageProcessor<float, double> processor(img1, img2, ROWS, COLS);
processor.processAndDisplay();
} catch (const exception& e) {
cerr << "Error: " << e.what() << endl;
}
return 0;
}