FAC1003 Tutorial 14 — OOP Solutions

Complete solutions for Tutorial 14 covering Object-Oriented Programming concepts, code tracing, and C++ applications.


Part 1: Concepts

Question 1: Define OOP and Contrast with Procedural Programming

Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around objects rather than functions and logic. Objects are instances of classes that bundle data (attributes) and behavior (methods) together.

Aspect Procedural Programming Object-Oriented Programming
Organization Functions/procedures operating on data Objects containing data + methods
Data Access Global/shared data Encapsulated (controlled access)
Reusability Limited (function libraries) High (inheritance, polymorphism)
Modularity Function-based Class-based
Real-world modeling Process-oriented Entity-oriented

Key difference:

  • Procedural: data and functions are separate
  • OOP: objects encapsulate both data and the functions that operate on it

Question 2: Encapsulation with C++ Example

Encapsulation is the bundling of data and methods that operate on that data within a single unit (class), while restricting direct access to some components.

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

class BankAccount {
private:
    string accountNumber;  // Hidden data
    double balance;        // Cannot be accessed directly
    
public:
    // Constructor
    BankAccount(string acc, double bal) {
        accountNumber = acc;
        balance = bal;
    }
    
    // Getter (controlled read access)
    double getBalance() {
        return balance;
    }
    
    // Setter with validation (controlled write access)
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposited: " << amount << endl;
        } else {
            cout << "Invalid amount!" << endl;
        }
    }
    
    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "Withdrawn: " << amount << endl;
        } else {
            cout << "Insufficient funds or invalid amount!" << endl;
        }
    }
};

int main() {
    BankAccount myAccount("ACC123", 1000.0);
    
    // myAccount.balance = 5000;  // ERROR: private member
    myAccount.deposit(500);       // OK: public method
    myAccount.withdraw(200);      // OK: public method
    
    cout << "Current balance: " << myAccount.getBalance() << endl;
    return 0;
}

Output:

Deposited: 500
Withdrawn: 200
Current balance: 1300

Question 3: Abstraction and Its Usefulness

Abstraction is the concept of hiding complex implementation details and showing only the essential features of an object.

Why it's useful:

  1. Simplifies complexity — Users interact with simple interfaces
  2. Reduces cognitive load — Focus on what, not how
  3. Improves maintainability — Implementation can change without affecting users
  4. Enables modularity — Clear separation of concerns

Example: A car driver uses the steering wheel and pedals (abstraction) without knowing how the engine works internally.

// Abstract class (interface)
class Vehicle {
public:
    virtual void start() = 0;    // Pure virtual — "what"
    virtual void stop() = 0;     // Implementation hidden — "how"
};

class Car : public Vehicle {
public:
    void start() { cout << "Car: Ignition on, engine running" << endl; }
    void stop() { cout << "Car: Braking, engine off" << endl; }
};

Question 4: Difference Between Inheritance and Polymorphism

Inheritance Polymorphism
"is-a" relationship "many forms" capability
Child class inherits from parent Same interface, different implementations
Creates class hierarchies Enables runtime behavior variation
Code reuse mechanism Flexibility mechanism

Inheritance Example:

class Animal {          // Base class
public:
    void eat() { cout << "Animal eats" << endl; }
};

class Dog : public Animal {  // Dog "is-a" Animal
public:
    void bark() { cout << "Dog barks" << endl; }
};

Polymorphism Example:

class Shape {
public:
    virtual double area() = 0;  // Same interface
};

class Circle : public Shape {
    double radius;
public:
    double area() { return 3.14159 * radius * radius; }  // Different implementation
};

class Rectangle : public Shape {
    double width, height;
public:
    double area() { return width * height; }  // Different implementation
};

Question 5: The Four Pillars of OOP

Pillar Description Purpose
1. Encapsulation Bundling data and methods; hiding internal state Data protection, controlled access
2. Abstraction Hiding implementation complexity Simplified interfaces
3. Inheritance Creating new classes from existing ones Code reuse, hierarchy
4. Polymorphism Same interface, different implementations Flexibility, extensibility

Question 6: Class and Object with Analogies

Class Object
Definition Blueprint/template Instance of a class
Analogy Car blueprint Your specific car
Analogy Cookie cutter The actual cookie
Analogy House architectural plan The built house
Memory No memory allocated Memory allocated when created
class Student {           // Class (blueprint)
    string name;
    int id;
public:
    void study() { }
};

Student ali;              // Object (instance)
Student sarah;            // Another object

Real-life analogies:

  • Class: Recipe for a cake
  • Object: The actual cake you baked using that recipe

Question 7: Constructor and Destructor Roles

Constructor:

  • Automatically called when object is created
  • Initializes object state
  • Same name as class, no return type

Destructor:

  • Automatically called when object is destroyed
  • Cleans up resources (memory, file handles)
  • Same name as class with ~ prefix
class MyClass {
    int* data;
    
public:
    // Constructor
    MyClass(int size) {
        data = new int[size];  // Allocate memory
        cout << "Constructor: Memory allocated" << endl;
    }
    
    // Destructor
    ~MyClass() {
        delete[] data;          // Free memory
        cout << "Destructor: Memory freed" << endl;
    }
};

Question 8: Three Types of Constructors

Type Syntax Purpose
1. Default Constructor ClassName() No arguments; creates object with default values
2. Parameterized Constructor ClassName(int x, int y) Accepts arguments; initializes with specific values
3. Copy Constructor ClassName(const ClassName& obj) Creates object as copy of existing object
class Box {
    int length, width;
    
public:
    // 1. Default Constructor
    Box() {
        length = 0;
        width = 0;
        cout << "Default constructor called" << endl;
    }
    
    // 2. Parameterized Constructor
    Box(int l, int w) {
        length = l;
        width = w;
        cout << "Parameterized constructor called" << endl;
    }
    
    // 3. Copy Constructor
    Box(const Box& b) {
        length = b.length;
        width = b.width;
        cout << "Copy constructor called" << endl;
    }
};

int main() {
    Box b1;              // Default constructor
    Box b2(10, 20);      // Parameterized constructor
    Box b3 = b2;         // Copy constructor
    return 0;
}

Part 2: Code Tracing

Question 9: Inheritance Code Tracing

Code:

class Animal {
public:
    void speak() { cout << "Animal speaks" << endl; }
};

class Dog : public Animal {
};

int main() {
    Dog d;
    d.speak();
    return 0;
}

Trace:

  1. Dog d; — Creates a Dog object. Since Dog inherits from Animal, it has access to Animal's public members.
  2. d.speak(); — Calls speak() method. Dog doesn't override speak(), so it uses Animal's version.

Output:

Animal speaks

Question 10: Constructor/Destructor Tracing

Code:

class A {
public:
    A() { cout << "Constructor"; }
    ~A() { cout << "Destructor"; }
};

int main() {
    A obj;
    return 0;
}

Trace:

  1. A obj; — Object obj is created → Constructor called immediately → Output: "Constructor"
  2. return 0; — Program ends, obj goes out of scope → Destructor called automatically → Output: "Destructor"

Output:

ConstructorDestructor

Note: Output appears on one line because no endl or \n is used.


Part 3: Applications

Question 11: Rectangle Class with Constructors and Destructor

Problem Requirements:

  • Private members: length, width
  • Public methods: area(), perimeter()
  • Constructor to initialize
  • Destructor to clean up
  • Main program creates two rectangles
#include <iostream>
using namespace std;

class Rectangle {
private:
    double length;
    double width;
    
public:
    // Constructor
    Rectangle(double l, double w) {
        length = l;
        width = w;
        cout << "Rectangle created (" << length << " x " << width << ")" << endl;
    }
    
    // Destructor
    ~Rectangle() {
        cout << "Rectangle destroyed (" << length << " x " << width << ")" << endl;
    }
    
    // Calculate area
    double area() {
        return length * width;
    }
    
    // Calculate perimeter
    double perimeter() {
        return 2 * (length + width);
    }
};

int main() {
    // Create two rectangle objects
    Rectangle rect1(5.0, 3.0);
    Rectangle rect2(10.0, 4.0);
    
    // Display area and perimeter for rect1
    cout << "\nRectangle 1:" << endl;
    cout << "  Area: " << rect1.area() << endl;
    cout << "  Perimeter: " << rect1.perimeter() << endl;
    
    // Display area and perimeter for rect2
    cout << "\nRectangle 2:" << endl;
    cout << "  Area: " << rect2.area() << endl;
    cout << "  Perimeter: " << rect2.perimeter() << endl;
    
    return 0;
}

Expected Output:

Rectangle created (5 x 3)
Rectangle created (10 x 4)

Rectangle 1:
  Area: 15
  Perimeter: 16

Rectangle 2:
  Area: 40
  Perimeter: 28
Rectangle destroyed (10 x 4)
Rectangle destroyed (5 x 3)

Question 12: Student Class with Getters/Setters and Average Calculation

Problem Requirements:

  • Private members: name, rollNumber, marks
  • Getter and setter methods
  • Static/class method to calculate average marks
  • Main program with array of students
#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;
    int rollNumber;
    double marks;
    
public:
    // Default constructor
    Student() {
        name = "";
        rollNumber = 0;
        marks = 0.0;
    }
    
    // Setters
    void setName(string n) { name = n; }
    void setRollNumber(int r) { rollNumber = r; }
    void setMarks(double m) { marks = m; }
    
    // Getters
    string getName() { return name; }
    int getRollNumber() { return rollNumber; }
    double getMarks() { return marks; }
    
    // Static method to calculate average
    static double calculateAverage(Student students[], int size) {
        double sum = 0;
        for (int i = 0; i < size; i++) {
            sum += students[i].getMarks();
        }
        return sum / size;
    }
};

int main() {
    const int NUM_STUDENTS = 3;
    Student students[NUM_STUDENTS];
    
    // Set values for each student
    students[0].setName("Ali");
    students[0].setRollNumber(101);
    students[0].setMarks(85.5);
    
    students[1].setName("Sarah");
    students[1].setRollNumber(102);
    students[1].setMarks(92.0);
    
    students[2].setName("John");
    students[2].setRollNumber(103);
    students[2].setMarks(78.5);
    
    // Display all students
    cout << "Student Records:" << endl;
    cout << "----------------" << endl;
    for (int i = 0; i < NUM_STUDENTS; i++) {
        cout << "Name: " << students[i].getName()
             << ", Roll: " << students[i].getRollNumber()
             << ", Marks: " << students[i].getMarks() << endl;
    }
    
    // Calculate and display average
    double average = Student::calculateAverage(students, NUM_STUDENTS);
    cout << "\nAverage Marks: " << average << endl;
    
    return 0;
}

Expected Output:

Student Records:
----------------
Name: Ali, Roll: 101, Marks: 85.5
Name: Sarah, Roll: 102, Marks: 92
Name: John, Roll: 103, Marks: 78.5

Average Marks: 85.3333

Question 13: Abstract Shape Class with Polymorphism

Problem Requirements:

  • Abstract Shape class with pure virtual functions
  • Rectangle and Circle derived classes
  • Array of Shape pointers
  • Calculate area and perimeter using virtual functions
#include <iostream>
#include <cmath>
using namespace std;

// Abstract base class
class Shape {
public:
    virtual double area() = 0;       // Pure virtual
    virtual double perimeter() = 0;   // Pure virtual
    virtual ~Shape() {}              // Virtual destructor
};

// Rectangle class
class Rectangle : public Shape {
private:
    double length, width;
    
public:
    Rectangle(double l, double w) : length(l), width(w) {}
    
    double area() override {
        return length * width;
    }
    
    double perimeter() override {
        return 2 * (length + width);
    }
};

// Circle class
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r) : radius(r) {}
    
    double area() override {
        return M_PI * radius * radius;
    }
    
    double perimeter() override {
        return 2 * M_PI * radius;
    }
};

int main() {
    const int NUM_SHAPES = 4;
    Shape* shapes[NUM_SHAPES];
    
    // Create objects and assign to shape pointers
    shapes[0] = new Rectangle(5.0, 3.0);
    shapes[1] = new Circle(4.0);
    shapes[2] = new Rectangle(10.0, 2.0);
    shapes[3] = new Circle(2.5);
    
    // Display area and perimeter for each shape
    cout << "Shape Calculations:" << endl;
    cout << "===================" << endl;
    
    for (int i = 0; i < NUM_SHAPES; i++) {
        cout << "Shape " << (i + 1) << ":" << endl;
        cout << "  Area: " << shapes[i]->area() << endl;
        cout << "  Perimeter: " << shapes[i]->perimeter() << endl;
        cout << endl;
    }
    
    // Clean up memory
    for (int i = 0; i < NUM_SHAPES; i++) {
        delete shapes[i];
    }
    
    return 0;
}

Expected Output:

Shape Calculations:
===================
Shape 1:
  Area: 15
  Perimeter: 16

Shape 2:
  Area: 50.2655
  Perimeter: 25.1327

Shape 3:
  Area: 20
  Perimeter: 24

Shape 4:
  Area: 19.635
  Perimeter: 15.708

Summary: Key OOP Concepts Tested

Concept Questions Covered
Encapsulation Q2, Q11, Q12
Inheritance Q4, Q9, Q13
Polymorphism Q4, Q13
Abstraction Q3, Q13
Constructors Q7, Q8, Q11
Destructors Q7, Q10, Q11
Getters/Setters Q12
Virtual Functions Q13

Related

  • FAC1003 - Programming II
  • Object-Oriented Programming (concept page if exists)
  • C++ Classes and Objects (concept page if exists)