0% found this document useful (0 votes)
4 views19 pages

OOP Spring 25 Final - Solution

The document outlines the final exam for Object-oriented Programming (CS-1004) at Karachi Campus, scheduled for May 19, 2025, with a total of 50 marks and 4 questions. It includes code snippets requiring error correction, output prediction, and completion of missing code segments, as well as a scenario involving a cyber operation requiring the design of an abstract class and data handling methods. The exam assesses students' understanding of object-oriented design and programming concepts in C++.

Uploaded by

smsarim6
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)
4 views19 pages

OOP Spring 25 Final - Solution

The document outlines the final exam for Object-oriented Programming (CS-1004) at Karachi Campus, scheduled for May 19, 2025, with a total of 50 marks and 4 questions. It includes code snippets requiring error correction, output prediction, and completion of missing code segments, as well as a scenario involving a cyber operation requiring the design of an abstract class and data handling methods. The exam assesses students' understanding of object-oriented design and programming concepts in C++.

Uploaded by

smsarim6
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
You are on page 1/ 19

Karachi Ca mpus

Object-oriented Programming (CS-1004) Final Exam

Date: 19/5/2025 Total Time: 3hrs


Course Instructor(s) Total Marks: 50
Basit Ali, Minhal, Sumaiya, Nida, Sobia, Abeeha, Atiya, Abeer, Bakhtawar.
Total Questions: 04

Roll No​ Section​ Student Signature

Do not write below this


Attempt all questions.
CLO 1: Identify real world problems in terms of objects rather than procedure​ [Marks 25, 60 min]
Q1:Part A: Find the errors and provide the corrected version of the codes given.
1.template <class T1,class T2> Solution
class myclass { #include <iostream>
T1 num1; using namespace std;
T2 num2; template <class
T1,class T2>
public:
class myclass {
myclass() {
T1 num1;
cout << "Default constructor" << endl; T2 num2;
} public:
myclass(T1 a, T2 b) { myclass() {
num1 = a; cout << "Default
num2 = b; constructor" <<
} endl;
void add() { num1 = T1(); //
int sum = num1 + num2; Initialize to default
value
cout << "The value of sum is " << sum; }
num2 = T1();
};
}
int main() { myclass(T1 a, T2 b) {
myclass obj1; num1 = a;
obj1.add(); num2 = b;
myclass<int> obj(3, 4); }
obj.add(); void add() {
return 0; int sum = num1 +
} num2;
cout << "The
value of sum is " <<
sum << endl;
}
};
int main() {
myclass<int,int> obj1;
obj1.add(); // Will
show 0 if both
default-initialized
myclass<int,int>
obj(3, 4);
obj.add();
return 0}
2 .class Complex { Solution
float real; #include <iostream>
float imag; using namespace std;
class Complex {
float real;
public:
float imag;
Complex(float r, float i) {
real = r; public:
imag = i; Complex(float r,
} float i) {
real = r;
Complex operator+(Complex c) { imag = i;
Complex temp; }
temp.real = real + c.real; Complex() : real(0),
temp.imag = imag + c.imag; imag(0) {}
Complex
return temp;
operator+(Complex
}
c) {
Complex temp;
void display() { temp.real = real +
cout << real << " + " << imag << "i" << endl; c.real;
} temp.imag = imag
}; + c.imag;
return temp;
int main() { }
Complex c1(3.2, 4.5), c2(1.1, 2.2); void display() {
Complex c3 = c1 + c2; cout << real << " +
" << imag << "i" <<
c3.display();
endl;
return 0;
}
} };

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;
​ } ​ }
};

Output: Output: Output:


100 Input.txt Contents: 0, 1
0, 1 Hello World!! 0, 1
Output.txt Contents: 0, 1
Hello World!! Hello World!!
Input.txt Contents:
Bye World!!
Output.txt Contents:
Bye World!! Bye World!!
Karachi Ca mpus

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>

using namespace std;

// Phase 6: Exception Handling War Room


class FileAccessException {
public:
const char* what() const {
return "File could not be opened!";
}
};
class ExtractionException {
public:
const char* what() const {
return "No high-risk records found for extraction!";
}
};

class DeleteTraceException {
public:
const char* what() const {
return "No traces marked as deleted!";
}
};

// Phase 1: Abstract Class Design


class CyberOperation {
public:
virtual void accessIntel() = 0; // Phase 3
virtual void extractPayload() = 0; // Phase 4
virtual void deleteTraces() = 0; // Phase 5
};

// Phase 2: IntelRecord Class


class IntelRecord {
int recordID;
char targetLocation[50];
int riskLevel;
char payload[100];
bool isDeleted;

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);

// Caesar cipher encryption (shift +3)


for (int i = 0; payload[i] != '\0'; i++) {
payload[i] = payload[i] + 3;
}

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;
}
};

// Full Operation Implementation


class Operation : public CyberOperation {
public:
void writeIntelToFile() {
ofstream outFile("intel.dat", ios::binary | ios::app);
if (!outFile) throw FileAccessException();

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);

if (!inFile || !outFile) throw FileAccessException();

IntelRecord rec;
bool found = false;

while (inFile.read((char*)&rec, sizeof(rec))) {


if (rec.getRiskLevel() >= 8) {
outFile.write((char*)&rec, sizeof(rec));
found = true;
}
}

inFile.close();
outFile.close();

if (!found) throw ExtractionException();


}

void deleteTraces() {
fstream file("intel.dat", ios::binary | ios::in | ios::out);
if (!file) throw FileAccessException();

IntelRecord rec;
bool deleted = false;
streampos pos;

while (file.read((char*)&rec, sizeof(rec))) {


if (rec.getRiskLevel() >= 8 && !rec.isMarkedDeleted()) {
pos = file.tellg();
rec.markDeleted();
file.seekp(pos - sizeof(rec)); // Move back to start of record
file.write((char*)&rec, sizeof(rec)); // Overwrite updated record
deleted = true;
}
}

file.close();

if (!deleted) throw DeleteTraceException();


}
};

// 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;
}

void addItem(const Product& product, int quantity) {


if (productCount < capacity && quantity > 0 && product.quantity >= quantity) {
int existingProductIndex = -1;
for(int i = 0; i < productCount; i++){
if(products[i].id == product.id){
existingProductIndex = i;
break;
}
}
0 if(existingProductIndex != -1){
products[existingProductIndex].quantity += quantity;
}
else{
0

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;

const int ROWS = 2;


const int COLS = 2;

template<typename T1, typename T2>


class ImagePixelCalculator{
private:
T1 img1[ROWS][COLS];
T2 img2[ROWS][COLS];
double result[ROWS][COLS];

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);
}

void setImage1(T1 img[ROWS][COLS]) {


for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
img1[i][j] = img[i][j];
}

void setImage2(T2 img[ROWS][COLS]) {


for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
img2[i][j] = img[i][j];
}

double (*getResult())[COLS] {
return result;
}

void printMatrix(double matrix[ROWS][COLS]) {


for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLS; ++j) {
cout << fixed << setprecision(2) << matrix[i][j] << "\t";
}
cout << endl;
}
cout << "------------------" << endl;
}

template<typename X = T1, typename Y = T2>


void denormalizeImage() {
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
result[i][j] = img1[i][j] + img2[i][j];
}

template<typename X = T1, typename Y = T2>


void normalizeImage() {
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
result[i][j] = img1[i][j] - img2[i][j];
}

template<typename X = T1, typename Y = T2>


void applyFilter() {
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
result[i][j] = img1[i][j] * img2[i][j];
}

template<typename X = T1, typename Y = T2>


void smoothImage() {
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
result[i][j] = (img1[i][j] + img2[i][j]) / 2.0;
}

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);

cout << "Normalized Image (Subtraction):" << endl;


normalizeImage();
printMatrix(result);

cout << "Filtered Image (Multiplication):" << endl;


applyFilter();
printMatrix(result);

cout << "Smoothed Image (Averaging):" << endl;


smoothImage();
printMatrix(result);

cout << "Transposed Image2:" << endl;


double transposed[ROWS][COLS];
transposeImage(img2, transposed);
printMatrix(transposed);
}
};

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;
}

You might also like