OOPs Practical Final
OOPs Practical Final
Design C++ classes with static members, methods with default arguments, and friend
functions. (for example, design matrix and vector classes with static allocation, and a
#include <vector>
class Vector {
private:
std::vector<double> elements;
public:
// Constructors
Vector() = default; // Default constructor
Vector(std::initializer_list<double> init) : elements(init) {}
// Method to get the size of the vector
static size_t size(const Vector& v) {
return v.elements.size();
}
// Friend function for matrix-vector multiplication
friend Vector matrixVectorMultiply(const Matrix& mat, const Vector& vec);
};
class Matrix {
private:
std::vector<std::vector<double>> elements;
public:
// Constructors
Matrix() = default; // Default constructor
Matrix(std::initializer_list<std::initializer_list<double>> init) : elements(init) {}
// Method to get the number of rows of the matrix
static size_t rows(const Matrix& mat) {
return mat.elements.size();
}
// Method to get the number of columns of the matrix
static size_t columns(const Matrix& mat) {
return (mat.elements.size() > 0) ? mat.elements[0].size() : 0;
}
// Friend function for matrix-vector multiplication
friend Vector matrixVectorMultiply(const Matrix& mat, const Vector& vec);
};
// Friend function implementation for matrix-vector multiplication
Vector matrixVectorMultiply(const Matrix& mat, const Vector& vec) {
// Check if the matrix and vector dimensions are compatible
if (Matrix::columns(mat) != Vector::size(vec)) {
std::cerr << "Error: Incompatible dimensions for matrix-vector multiplication." << std::endl;
return Vector(); // Return an empty vector in case of error
}
Vector result;
// Perform matrix-vector multiplication
for (size_t i = 0; i < Matrix::rows(mat); ++i) {
double sum = 0.0;
for (size_t j = 0; j < Matrix::columns(mat); ++j) {
sum += mat.elements[i][j] * vec.elements[j];
}
result.elements.push_back(sum);
}
return result;
}
int main() {
// Example usage
Matrix matrix({{1, 2, 3}, {4, 5, 6}});
Vector vector({2, 3, 4});
// Perform matrix-vector multiplication
Vector result = matrixVectorMultiply(matrix, vector);
// Display the result
std::cout << "Result of matrix-vector multiplication:" << std::endl;
for (double value : result.elements) {
std::cout << value << " ";
}
std::cout << std::endl;
return 0;
}
Output:
2. Implement matrix class with dynamic memory allocation and necessary methods. Give
operator.
#include <iostream>
#include <stdexcept>
class Matrix {
private:
size_t rows;
size_t columns;
double** elements;
public:
// Constructors
Matrix(size_t rows, size_t columns) : rows(rows), columns(columns) {
// Allocate memory for the matrix
elements = new double*[rows];
for (size_t i = 0; i < rows; ++i) {
elements[i] = new double[columns];
}
// Initialize elements to 0
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
elements[i][j] = 0.0;
}
}
}
// Destructor
~Matrix() {
// Deallocate memory for the matrix
for (size_t i = 0; i < rows; ++i) {
delete[] elements[i];
}
delete[] elements;
}
// Copy constructor
Matrix(const Matrix& other) : rows(other.rows), columns(other.columns) {
// Allocate memory for the new matrix
elements = new double*[rows];
for (size_t i = 0; i < rows; ++i) {
elements[i] = new double[columns];
}
// Copy elements from the other matrix
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
elements[i][j] = other.elements[i][j];
}
}
}
// Overloading the assignment operator
Matrix& operator=(const Matrix& other) {
if (this != &other) {
// Deallocate existing memory
for (size_t i = 0; i < rows; ++i) {
delete[] elements[i];
}
delete[] elements;
// Copy size
rows = other.rows;
columns = other.columns;
// Allocate new memory
elements = new double*[rows];
for (size_t i = 0; i < rows; ++i) {
elements[i] = new double[columns];
}
// Copy elements from the other matrix
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
elements[i][j] = other.elements[i][j];
}
}
}
return *this;
}
// Method to get the number of rows
size_t getRows() const {
return rows;
}
// Method to get the number of columns
size_t getColumns() const {
return columns;
}
// Method to access elements
double& at(size_t row, size_t col) {
if (row >= rows || col >= columns) {
throw std::out_of_range("Matrix indices out of range");
}
return elements[row][col];
}
// Method to display the matrix
void display() const {
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
std::cout << elements[i][j] << " ";
}
std::cout << std::endl;
}
}
};
int main() {
// Example usage
Matrix mat1(2, 3);
mat1.at(0, 0) = 1.0;
mat1.at(0, 1) = 2.0;
mat1.at(0, 2) = 3.0;
mat1.at(1, 0) = 4.0;
mat1.at(1, 1) = 5.0;
mat1.at(1, 2) = 6.0;
Matrix mat2 = mat1; // Copy constructor
Matrix mat3(3, 2);
mat3 = mat1; // Overloaded assignment operator
// Display matrices
std::cout << "Matrix 1:" << std::endl;
mat1.display();
std::cout << "Matrix 2 (copy of Matrix 1 using copy constructor):" << std::endl;
mat2.display();
std::cout << "Matrix 3 (assigned from Matrix 1 using overloaded assignment operator):" << std::endl;
mat3.display();
return 0;
}
Output:
3. Implement complex number class with necessary operator overloading and type
#include <iostream>
#include <cmath>
class Complex {
private:
double real;
double imag;
public:
// Constructors
Complex() : real(0.0), imag(0.0) {}
Complex(double r, double i) : real(r), imag(i) {}
// Getter functions
double getReal() const { return real; }
double getImag() const { return imag; }
int main() {
// Example usage of the Complex class
Complex c1(3.0, 4.0);
Complex c2(1.5, 2.5);
// Arithmetic operations
Complex sum = c1 + c2;
Complex diff = c1 - c2;
Complex product = c1 * c2;
Complex quotient = c1 / c2;
// Type conversions
double c1AsDouble = static_cast<double>(c1);
int c2AsInt = static_cast<int>(c2);
return 0;
}
Output:
4. Overload the new and delete operators to provide a custom dynamic allocation of
memory.
#include <iostream>
#include <new>
class Matrix {
private:
size_t rows;
size_t columns;
double** elements;
public:
// Overloaded new operator for custom memory allocation
void* operator new(std::size_t size) {
std::cout << "Custom new operator called. Size: " << size << std::endl;
return ::operator new(size);
}
int main() {
// Example usage
Matrix* mat = new Matrix(2, 3);
return 0;
}
Output:
5. Develop C++ class hierarchy for various types of inheritances.
#include <iostream>
// Base class
class Animal {
public:
void eat() {
std::cout << "Animal is eating." << std::endl;
}
void sleep() {
std::cout << "Animal is sleeping." << std::endl;
}
};
// Single Inheritance
class Dog : public Animal {
public:
void bark() {
std::cout << "Dog is barking." << std::endl;
}
};
// Multiple Inheritance
class Bird {
public:
void fly() {
std::cout << "Bird is flying." << std::endl;
}
};
class FlyingDog : public Dog, public Bird {
public:
// Inherits both bark() from Dog and fly() from Bird
};
// Hierarchical Inheritance
class Cat : public Animal {
public:
void meow() {
std::cout << "Cat is meowing." << std::endl;
}
};
// Multilevel Inheritance
class Kitten : public Cat {
public:
void play() {
std::cout << "Kitten is playing." << std::endl;
}
};
int main() {
// Single Inheritance example
Dog myDog;
myDog.eat(); // Inherited from Animal
myDog.sleep(); // Inherited from Animal
myDog.bark(); // Specific to Dog
// Multiple Inheritance example
FlyingDog flyingDog;
flyingDog.eat(); // Inherited from Animal
flyingDog.sleep(); // Inherited from Animal
flyingDog.bark(); // Inherited from Dog
flyingDog.fly(); // Inherited from Bird
return 0;
}
Output:
6. Design a simple test application to demonstrate dynamic polymorphism and RTTI
#include <iostream>
#include <vector>
#include <typeinfo>
// Base class
class Shape {
public:
virtual void draw() const {
std::cout << "Drawing a shape." << std::endl;
}
int main() {
// Create a vector of shapes using dynamic polymorphism
std::vector<Shape*> shapes;
shapes.push_back(new Circle());
shapes.push_back(new Rectangle());
shapes.push_back(new Circle());
shapes.push_back(new Rectangle());
return 0;
}
Output:
7. Develop a template of the linked-list class and its methods.
#include <iostream>
public:
// Constructor
LinkedList() : head(nullptr) {}
// Destructor
~LinkedList() {
clear();
}
current->next = newNode;
}
// Function to delete the first occurrence of a value in the list
void remove(const T& value) {
if (head == nullptr) {
return;
}
if (head->data == value) {
Node* temp = head;
head = head->next;
delete temp;
return;
}
if (current->next != nullptr) {
Node* temp = current->next;
current->next = current->next->next;
delete temp;
}
}
int main() {
// Example usage of the LinkedList template
LinkedList<int> intList;
intList.insertEnd(1);
intList.insertEnd(2);
intList.insertFront(0);
intList.display(); // Output: 0 1 2
intList.remove(1);
intList.display(); // Output: 0 2
return 0;
}
Output:
8. Develop templates of standard sorting algorithms such as bubble sort, insertion sort and
quick sort.
➢ Bubble Sort
#include <iostream>
#include <vector>
int main() {
// Example usage of bubbleSort template
std::vector<int> intArray = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(intArray);
std::cout << "Sorted array: ";
for (const auto& elem : intArray) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
Output:
➢ Insertion Sort
#include <iostream>
#include <vector>
int main() {
// Example usage of insertionSort template
std::vector<int> intArray = {64, 34, 25, 12, 22, 11, 90};
insertionSort(intArray);
std::cout << "Sorted array: ";
for (const auto& elem : intArray) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
Output:
➢ Quick Sort
#include <iostream>
#include <vector>
if (pivotIndex > 0) {
quickSort(arr, low, pivotIndex - 1);
}
➢ Stack Class
#include <iostream>
#include <stdexcept>
#include <vector>
public:
// Push an element onto the stack
void push(const T& value) {
elements.push_back(value);
}
int main() {
// Example usage of Stack class
Stack<int> intStack;
try {
intStack.push(10);
intStack.push(20);
intStack.push(30);
while (!intStack.empty()) {
intStack.pop();
}
return 0;
}
Output:
➢ Queue Class
#include <iostream>
#include <stdexcept>
#include <queue>
public:
// Enqueue an element into the queue
void enqueue(const T& value) {
elements.push(value);
}
int main() {
// Example usage of Queue class
Queue<int> intQueue;
try {
intQueue.enqueue(10);
intQueue.enqueue(20);
intQueue.enqueue(30);
while (!intQueue.empty()) {
intQueue.dequeue();
}
return 0;
}
Output:
10. Write a C++ program that randomly generates complex numbers (use previously
designed complex class ) and write them two per line in a file along with an operator (+,-
,*, or /). The numbers are written to file in the format (a+ib). Write another program to
#include <iostream>
#include <fstream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
#include <sstream>
#include <vector>
#include <string>
int main() {
// Seed the random number generator
srand(static_cast<unsigned>(time(nullptr)));
// Open a file for writing
std::ofstream outFile("complex_numbers.txt");
// Write two complex numbers and an operator per line to the file
for (int i = 0; i < 5; ++i) {
Complex c1 = generateRandomComplex();
Complex c2 = generateRandomComplex();
char op = generateRandomOperator();
outFile << c1 << " " << op << " " << c2 << std::endl;
}
return 0;
}
Output: