2080

BIT153 · TU past paper

Object Oriented Programming 2080 question paper

The complete TU 2080 exam paper for Object Oriented Programming (BIT153), all 12 questions with solved model answers written to the mark scheme.

Tap a question to open its answer.

  1. 110 marksConstructor definition and purposeAnswer

    What is constructor? Explain its types with suitable example.How is the constructor called in a derived class in C++?[6+4]

    Constructor in C++

    What is a Constructor?

    A constructor is a special member function of a class that is automatically called when an object of that class is created. It is used to initialize the data members of the class.

    Key Characteristics:

    • Has the same name as the class
    • Has no return type (not even void)
    • Called automatically when an object is created
    • Can be overloaded

    Types of Constructors

    1. Default Constructor

    A constructor that takes no arguments. If no constructor is defined, the compiler provides one automatically.

    #include<iostream>
    using namespace std;
    
    class Student {
        int roll;
        string name;
    public:
        // Default Constructor
        Student() {
            roll = 0;
            name = "Unknown";
            cout << "Default Constructor called" << endl;
        }
        void display() {
            cout << "Roll: " << roll << ", Name: " << name << endl;
        }
    };
    
    int main() {
        Student s1;   // Default constructor called automatically
        s1.display();
        return 0;
    }
    

    Output:

    Default Constructor called
    Roll: 0, Name: Unknown
    

    2. Parameterized Constructor

    A constructor that accepts one or more arguments to initialize objects with specific values.

    #include<iostream>
    using namespace std;
    
    class Student {
        int roll;
        string name;
    public:
        // Parameterized Constructor
        Student(int r, string n) {
            roll = r;
            name = n;
            cout << "Parameterized Constructor called" << endl;
        }
        void display() {
            cout << "Roll: " << roll << ", Name: " << name << endl;
        }
    };
    
    int main() {
        Student s1(101, "Ram");   // Parameterized constructor called
        s1.display();
        return 0;
    }
    

    Output:

    Parameterized Constructor called
    Roll: 101, Name: Ram
    

    3. Copy Constructor

    A constructor that creates a new object as a copy of an existing object. It takes a reference to an object of the same class as its argument.

    #include<iostream>
    using namespace std;
    
    class Student {
        int roll;
        string name;
    public:
        Student(int r, string n) {
            roll = r;
            name = n;
        }
        // Copy Constructor
        Student(const Student &s) {
            roll = s.roll;
            name = s.name;
            cout << "Copy Constructor called" << endl;
        }
        void display() {
            cout << "Roll: " << roll << ", Name: " << name << endl;
        }
    };
    
    int main() {
        Student s1(101, "Ram");
        Student s2(s1);    // Copy constructor called
        s2.display();
        return 0;
    }
    

    Output:

    Copy Constructor called
    Roll: 101, Name: Ram
    

    4. Constructor Overloading

    Multiple constructors with different parameter lists in the same class.

    #include<iostream>
    using namespace std;
    
    class Rectangle {
        float length, breadth;
    public:
        Rectangle() {              // Default
            length = breadth = 0;
        }
        Rectangle(float l, float b) {   // Parameterized
            length = l;
            breadth = b;
        }
        void area() {
            cout << "Area = " << length * breadth << endl;
        }
    };
    
    int main() {
        Rectangle r1;           // calls default constructor
        Rectangle r2(5.0, 3.0); // calls parameterized constructor
        r1.area();
        r2.area();
        return 0;
    }
    

    Calling Constructor in a Derived Class

    When a derived class object is created, both the base class constructor and the derived class constructor are called. The base class constructor is called first, then the derived class constructor.

    To explicitly pass arguments to the base class constructor, we use an initializer list with the colon (:) syntax.

    Syntax:

    DerivedClass(parameters) : BaseClass(arguments) {
        // derived class constructor body
    }
    

    Order of Execution:

    1. Base class constructor executes first
    2. Derived class constructor executes next

    Example:

    #include<iostream>
    using namespace std;
    
    // Base Class
    class Animal {
        string name;
    public:
        Animal(string n) {
            name = n;
            cout << "Animal Constructor: " << name << endl;
        }
    };
    
    // Derived Class
    class Dog : public Animal {
        string breed;
    public:
        // Calling base class constructor using initializer list
        Dog(string n, string b) : Animal(n) {
            breed = b;
            cout << "Dog Constructor: Breed = " << breed << endl;
        }
    };
    
    int main() {
        Dog d1("Tommy", "Labrador");
        return 0;
    }
    

    Output:

    Animal Constructor: Tommy
    Dog Constructor: Breed = Labrador
    

    Key Points:

    AspectDetail
    Base constructor callAlways called before derived constructor
    SyntaxDerived(params) : Base(args) { }
    Default base constructorCalled automatically if not specified
    Destructor orderReverse of constructor order

    Note: If the base class has only a parameterized constructor (no default constructor), the derived class must explicitly call it using the initializer list, otherwise a compile-time error occurs.

  2. 210 marksVirtual functionsAnswer

    What is Polymorphism in Object Oriented Programming? Implement a class Employee with a virtual function CalculateSalary() that returns the salary of the employee. Create two derived classes HourlyEmployee and SalariedEmployee. Override the CalculateSalary() function in both derived classes to calculate the salary of an hourly employee and a salaried employee respectively. Write a program that creates objects of both derived classes and calls the CalculateSalary() function for each.[10]

    Polymorphism in OOP and Virtual Function Implementation

    What is Polymorphism?

    Polymorphism is one of the four fundamental pillars of Object Oriented Programming (along with Encapsulation, Inheritance, and Abstraction). The word polymorphism comes from Greek meaning "many forms".

    In OOP, polymorphism means the ability of a single interface (function name or operator) to behave differently depending on the object that invokes it.

    Types of Polymorphism

    TypeAlso Known AsResolved At
    Compile-time PolymorphismStatic / Early BindingCompile time
    Run-time PolymorphismDynamic / Late BindingRun time
    • Compile-time polymorphism is achieved through function overloading and operator overloading.
    • Run-time polymorphism is achieved through virtual functions and function overriding (inheritance).

    Key Concepts for Run-time Polymorphism

    • Virtual Function: A function declared with the keyword virtual in the base class. It tells the compiler to resolve the function call at run time based on the actual object type, not the pointer/reference type.
    • Override: Redefining a virtual function in a derived class with the same signature.
    • Base class pointer can point to derived class objects, and the correct overridden function is called automatically (dynamic dispatch).

    C++ Program Implementation

    #include <iostream>
    using namespace std;
    
    // -----------------------------------------------
    // Base Class: Employee
    // -----------------------------------------------
    class Employee {
    protected:
        string name;
    
    public:
        // Constructor
        Employee(string empName) {
            name = empName;
        }
    
        // Virtual function to be overridden in derived classes
        virtual double CalculateSalary() {
            return 0.0;
        }
    
        // Virtual display function
        virtual void display() {
            cout << "Employee Name : " << name << endl;
            cout << "Salary        : Rs. " << CalculateSalary() << endl;
        }
    
        // Virtual destructor (good practice with virtual functions)
        virtual ~Employee() {}
    };
    
    // -----------------------------------------------
    // Derived Class 1: HourlyEmployee
    // Salary = hoursWorked * hourlyRate
    // -----------------------------------------------
    class HourlyEmployee : public Employee {
    private:
        double hoursWorked;
        double hourlyRate;
    
    public:
        // Constructor
        HourlyEmployee(string empName, double hours, double rate)
            : Employee(empName) {
            hoursWorked = hours;
            hourlyRate  = rate;
        }
    
        // Override CalculateSalary()
        double CalculateSalary() override {
            return hoursWorked * hourlyRate;
        }
    
        void display() override {
            cout << "----- Hourly Employee -----" << endl;
            cout << "Employee Name : " << name        << endl;
            cout << "Hours Worked  : " << hoursWorked << endl;
            cout << "Hourly Rate   : Rs. " << hourlyRate << endl;
            cout << "Total Salary  : Rs. " << CalculateSalary() << endl;
        }
    };
    
    // -----------------------------------------------
    // Derived Class 2: SalariedEmployee
    // Salary = fixedMonthlySalary (fixed, no calculation needed)
    // -----------------------------------------------
    class SalariedEmployee : public Employee {
    private:
        double monthlySalary;
    
    public:
        // Constructor
        SalariedEmployee(string empName, double salary)
            : Employee(empName) {
            monthlySalary = salary;
        }
    
        // Override CalculateSalary()
        double CalculateSalary() override {
            return monthlySalary;
        }
    
        void display() override {
            cout << "----- Salaried Employee -----" << endl;
            cout << "Employee Name   : " << name          << endl;
            cout << "Monthly Salary  : Rs. " << CalculateSalary() << endl;
        }
    };
    
    // -----------------------------------------------
    // Main Function
    // -----------------------------------------------
    int main() {
    
        // Create objects of derived classes
        HourlyEmployee  emp1("Ram Sharma",   160, 150.0);  // 160 hrs, Rs.150/hr
        SalariedEmployee emp2("Sita Thapa",  55000.0);     // Fixed Rs.55000/month
    
        // Call display (which internally calls CalculateSalary)
        emp1.display();
        cout << endl;
        emp2.display();
        cout << endl;
    
        // Demonstrating Run-time Polymorphism using Base class pointer
        cout << "=== Run-time Polymorphism Demo ===" << endl;
    
        Employee* empPtr;   // Base class pointer
    
        empPtr = &emp1;     // Points to HourlyEmployee object
        cout << "Salary (via base pointer): Rs. " << empPtr->CalculateSalary() << endl;
    
        empPtr = &emp2;     // Points to SalariedEmployee object
        cout << "Salary (via base pointer): Rs. " << empPtr->CalculateSalary() << endl;
    
        return 0;
    }
    

    Expected Output

    ----- Hourly Employee -----
    Employee Name : Ram Sharma
    Hours Worked  : 160
    Hourly Rate   : Rs. 150
    Total Salary  : Rs. 24000
    
    ----- Salaried Employee -----
    Employee Name   : Sita Thapa
    Monthly Salary  : Rs. 55000
    
    === Run-time Polymorphism Demo ===
    Salary (via base pointer): Rs. 24000
    Salary (via base pointer): Rs. 55000
    

    Explanation of Key Points

    ConceptWhere Used
    virtual keywordDeclared in Employee::CalculateSalary()
    override keywordUsed in both derived classes (C++11)
    Dynamic DispatchBase class pointer empPtr calls correct version at run time
  3. 310 marksOperator overloading definition and purposAnswer

    What is operator overloading? Write a complete C++ program to overload + operator to add two objects of class 'Time'.[10]

    Operator overloading is a feature of C++ that allows the programmer to redefine or extend the meaning of existing operators (such as +, -, , ==, etc.) for user-defined data types (classes and structures). It enables objects of a class to...

  4. 45 marksPublic, private, and protected inheritanceAnswer

    What is the difference between public, private and protected inheritance in C++? [5]

    In C++, when a derived class inherits from a base class, an access specifier is used to control how the inherited members are accessible in the derived class and further down the hierarchy. Syntax: --- The inherited member's accessibilit...

  5. 55 marksException handling definition and purposeAnswer

    What is exception handling? Explain types of exception handling and explain with suitable example. [5]

    Exception Handling in C++

    What exception handling is

    Exception handling is the mechanism by which a C++ program reports a fault at the point where it is detected and deals with it at the point where there is enough context to decide what to do. The detecting code executes throw, which creates an exception object; the runtime then searches outward through the enclosing try blocks for a catch handler whose type matches, destroying every local object it passes on the way. That destruction, called stack unwinding, is what makes the mechanism safe.

    The result is a clean split: the ordinary logic stays in the try block and the recovery logic sits in the handlers, instead of an error test being wedged in after every call.

    The constructs C++ provides

    ConstructPurpose
    tryEncloses code whose exceptions are to be handled
    catchHandles one type of exception; several may follow one try
    throwRaises an exception, or rethrows the current one when written bare
    catch (...)Catches an exception of any type at all
    noexceptPromises a function throws nothing, so the compiler may optimise accordingly

    There is deliberately no finally in this list. C++ does not have one, because cleanup belongs in the destructor of the object that owns the resource, and destructors are run automatically during unwinding.

    The standard exception hierarchy

    Most thrown types derive from std::exception, declared in <exception>, which offers the single member what() returning a description. Two broad families sit under it, in <stdexcept>:

    • Logic errors, faults a correct program should have prevented: std::logic_error, and under it std::invalid_argument, std::out_of_range, std::domain_error, std::length_error.
    • Runtime errors, faults only detectable while running: std::runtime_error, and under it std::overflow_error, std::underflow_error, std::range_error.

    std::bad_alloc from a failed new and std::bad_cast from a failed dynamic_cast on a reference also derive from std::exception. Because they share a base, one handler for const std::exception& can catch the whole family.

    Forms exception handling takes

    A single try with one handler

    #include <iostream>
    #include <stdexcept>
    
    int divide(int a, int b) {
        if (b == 0)
            throw std::runtime_error("division by zero");   // C++ does not throw here by itself
        return a / b;
    }
    
    int main() {
        try {
            std::cout << divide(10, 0) << "\n";
        } catch (const std::runtime_error& e) {
            std::cout << "Error: " << e.what() << "\n";
        }
    }
    

    Integer division by zero is undefined behaviour in C++, not an automatic exception, so the divisor is tested and the exception thrown on purpose. Anyone coming from Java should note that there is no ArithmeticException here to rely on.

    Several handlers on one try

    Handlers are tried in order and the first matching one wins, so the most derived type must be written first. A base class handler placed above a derived one would swallow it.

    #include <iostream>
    #include <vector>
    #include <stdexcept>
    
    int main() {
        std::vector<int> v{10, 20, 30, 40, 50};
        try {
            std::cout << v.at(2) << "\n";   // fine
            std::cout << v.at(10) << "\n";  // at() checks the index and throws
        }
        catch (const std::out_of_range& e) {          // most derived first
            std::cout << "Index error: " << e.what() << "\n";
        }
        catch (const std::exception& e) {             // then the general case
            std::cout << "Other error: " << e.what() << "\n";
        }
        catch (...) {                                 // anything not derived from std::exception
            std::cout << "Unknown error\n";
        }
    }
    

    A raw array subscript is not checked by C++ and throws nothing, so v[10] on a plain array would simply corrupt memory. std::vector::at() performs the bounds test and throws std::out_of_range, which is why it is used here.

    Throwing an exception of your own

    Deriving from std::runtime_error costs one line and gives the new type a working what().

    #include <iostream>
    #include <stdexcept>
    #include <string>
    
    class NotEligible : public std::runtime_error {
    public:
        explicit NotEligible(const std::string& msg) : std::runtime_error(msg) {}
    };
    
    void checkAge(int age) {
        if (age < 18)
            throw NotEligible("not eligible to vote");
        std::cout << "Eligible to vote\n";
    }
    
    int main() {
        try {
            checkAge(15);
        } catch (const NotEligible& e) {
            std::cout << "Caught: " << e.what() << "\n";
        }
    }
    

    Output:

    Caught: not eligible to vote
    

    Cleanup, which is where RAII replaces finally

    #include <iostream>
    #include <fstream>
    #include <stdexcept>
    #include <string>
    
    class LogFile {
        std::ofstream out;
    public:
        explicit LogFile(const std::string& name) : out(name) {
            std::cout << "Log opened\n";
        }
        ~LogFile() { std::cout << "Log closed\n"; }   // runs even while an exception propagates
        void write(const std::string& s) { out << s << "\n"; }
    };
    
    int main() {
        try {
            LogFile log("run.txt");
            log.write("working");
            throw std::runtime_error("something failed");
        } catch (const std::exception& e) {
            std::cout << "Error: " << e.what() << "\n";
        }
        std::cout << "Program continues\n";
    }
    

    Output:

    Log opened
    Log closed
    Error: something failed
    Program continues
    

    The destructor of log runs during unwinding, before the handler body, so the resource is released with no cleanup code written at the call site. A std::unique_ptr or a std::lock_guard gives the same guarantee for heap memory and for mutexes.

    Points of practice

    Catch by const reference, never by value, since catching a base class by value slices away the derived part of the exception object. Order handlers from most derived to most general. Never let an exception escape a destructor, because unwinding while another exception is active calls std::terminate. Throw only for genuinely exceptional conditions, and use a return value or std::optional for outcomes that are expected.

    Taken together, try, catch, throw, and the destructors that run during unwinding give C++ a complete error handling mechanism: the fault is reported where it is seen, handled where it can be dealt with, and every resource acquired in between is released on the way out.

  6. 65 marksFriend functionsAnswer

    What is friend function? Write a program to add private member of two different classes using friend function. [5]

    A friend function is a function that is not a member of a class but has access to the private and protected members of that class. It is declared inside the class using the keyword friend, but it is defined outside the class like a norma...

  7. 75 marksReturning objects from functionsAnswer

    Write a program to demonstrate returning object from functions in C++. [5]

    In C++, a function can return an object of a class just like it returns any other data type. The returned object is a copy of the local object created inside the function. Point Explanation -------------------- Return type The return typ...

  8. 85 marksThis pointer for name conflict resolutionAnswer

    How 'this' pointer is used to resolve name conflict between local variable and member variable in C++? Explain with example. [5]

    The this pointer is an implicit pointer available inside every non-static member function of a class. It automatically holds the address of the object that called the member function. Its type is ClassName. --- A name conflict arises whe...

  9. 95 marksFile handling with objectsAnswer

    Write a Program to read and write values through object using File Handling. [5]

    File handling in C++ allows storing and retrieving object data (attributes) to/from files using fstream. We use write() to store binary data and read() to retrieve it. --- --- --- Feature Description ------ fstream Used for both reading ...

  10. 105 marksClass templatesAnswer

    What do you mean by class template in C++? Write a program in C++ containing function template which determines the greater number between two integer inputs and two floating point inputs. [5]

    A class template in C++ is a blueprint for creating a family of classes where the data type is parameterized. Instead of writing separate classes for different data types, a single class template can be defined and the compiler generates...

  11. 115 marksFunction overridingAnswer

    Differentiate between function overloading and function overriding in C++. [5]

    --- Function overloading means defining multiple functions with the same name but with different parameter lists (different number, type, or order of parameters) within the same class or scope. - Resolved at compile time (Static/Early Bi...

  12. 125 marksStatic data members and static functionsAnswer

    Illustrate the use of static variable with a simple program. [5]

    A static variable is a variable that retains its value between function calls. It is initialized only once (at the first call) and exists for the entire lifetime of the program, even though its scope may be local to a function. --- Prope...