CSC166 · TU past paper
Object Oriented Programming 2080 question paper
The complete TU 2080 exam paper for Object Oriented Programming (CSC166), all 12 questions with solved model answers written to the mark scheme.
Tap a question to open its answer.
- 110 marksTypes of inheritanceHideAnswer
State the use of new operator. An educational institute wishes to maintain a data of its employee. The hierarchical relationships of related classes are as follows. Define all the classes to represent above hierarchy and define functions to retrieve individual information as and when required.[10]
New Operator and Employee Hierarchy in C++
Use of
newOperator (2 marks)The
newoperator in C++ is used for dynamic memory allocation. It allocates memory at runtime from the heap (free store) and returns a pointer to the beginning of the allocated memory block.Key uses:
- Allocates memory for a variable or object during program execution
- Returns a pointer to the allocated memory
- Memory persists until explicitly released using
delete - Syntax:
pointer_variable = new data_type;
Example:
int *ptr = new int; // allocates memory for one integer int *arr = new int[10]; // allocates memory for array of 10 integers delete ptr; // free single variable delete[] arr; // free array
Employee Hierarchy Program (8 marks)
Class Hierarchy Structure
Employee (name, emp_id) | ________________ | | Teacher Officer (subject, (department, salary) salary) | Typist (speed, salary)
Complete C++ Program
#include<iostream> #include<string> using namespace std; // ─── Base Class ─────────────────────────────────────────────── class Employee { protected: string name; int emp_id; public: // Function to set employee data void getEmployeeData() { cout << "Enter Employee Name: "; cin >> name; cout << "Enter Employee ID: "; cin >> emp_id; } // Function to display employee data void showEmployeeData() { cout << "\n--- Employee Information ---" << endl; cout << "Name : " << name << endl; cout << "Emp ID : " << emp_id << endl; } }; // ─── Derived Class: Teacher ──────────────────────────────────── class Teacher : public Employee { protected: string subject; float salary; public: // Function to set teacher data void getTeacherData() { getEmployeeData(); // call base class function cout << "Enter Subject Specialization: "; cin >> subject; cout << "Enter Salary: "; cin >> salary; } // Function to display teacher data void showTeacherData() { showEmployeeData(); // call base class function cout << "Subject : " << subject << endl; cout << "Salary : " << salary << endl; } }; // ─── Derived Class: Typist (derived from Teacher) ───────────── class Typist : public Teacher { private: int typingSpeed; // words per minute public: // Function to set typist data void getTypistData() { getTeacherData(); cout << "Enter Typing Speed (wpm): "; cin >> typingSpeed; } // Function to display typist data void showTypistData() { showTeacherData(); cout << "Typing Speed: " << typingSpeed << " wpm" << endl; } }; // ─── Derived Class: Officer ──────────────────────────────────── class Officer : public Employee { private: string department; float salary; public: // Function to set officer data void getOfficerData() { getEmployeeData(); // call base class function cout << "Enter Department: "; cin >> department; cout << "Enter Salary: "; cin >> salary; } // Function to display officer data void showOfficerData() { showEmployeeData(); // call base class function cout << "Department: " << department << endl; cout << "Salary : " << salary << endl; } }; // ─── Main Function ───────────────────────────────────────────── int main() { int choice; cout << "===== Educational Institute Employee System =====" << endl; cout << "1. Teacher\n2. Typist\n3. Officer" << endl; cout << "Enter your choice: "; cin >> choice; // Using new operator for dynamic object creation if (choice == 1) { Teacher *t = new Teacher; t->getTeacherData(); t->showTeacherData(); delete t; } else if (choice == 2) { Typist *ty = new Typist; ty->getTypistData(); ty->showTypistData(); delete ty; } else if (choice == 3) { Officer *o = new Officer; o->getOfficerData(); o->showOfficerData(); delete o; } else { cout << "Invalid choice!" << endl; } return 0; }
Sample Output
===== Educational Institute Employee System ===== 1. Teacher 2. Typist 3. Officer Enter your choice: 1 Enter Employee Name: Ram Enter Employee ID: 101 Enter Subject Specialization: Mathematics Enter Salary: 45000 --- Employee Information --- Name : Ram Emp ID : 101 Subject : Mathematics Salary : 45000
Key Concepts Used
Concept Application Base Class Employeeholds common data (name, emp_id)Inheritance Teacher,Officerinherit fromEmployee;Typistinherits fromTeacherprotectedmembersAllow derived classes to access base class data directly newoperatorUsed to create objects dynamically at runtime Function overriding Each derived class defines its own showandgetfunctionspublicinheritanceDerived class inherits all publicandprotectedmembers of base class**
- 210 marksInitialization of class objectsHideAnswer
What is constructor? Why constructor is needed in a class? Illustrate the types of constructor with an example.[10]
Constructor in C++
Definition of Constructor
A constructor is a special member function of a class that is automatically called when an object of that class is created. It has the same name as the class and is used to initialize the data members of the class.
Key Characteristics of a Constructor:
- It has the same name as the class
- It has no return type (not even
void) - It is called automatically when an object is created
- It cannot be inherited, but a derived class can call the base class constructor
- It can be overloaded
Why is a Constructor Needed in a Class?
When an object is created, its data members may contain garbage values if not initialized. A constructor is needed because:
- Automatic Initialization: It automatically initializes data members when an object is created, avoiding garbage values.
- Memory Allocation: It can allocate dynamic memory using the
newoperator at the time of object creation. - No Manual Call Required: Unlike regular functions, the programmer does not need to explicitly call it; it runs automatically.
- Ensures Valid State: It ensures that an object always starts in a valid, well-defined state.
- Resource Acquisition: It can open files, establish connections, or acquire any resources needed by the object.
As seen in the notes, a class like
stringuses a constructorstring(char *c)to allocate memory usingnewand copy data, ensuring the object is properly set up from the moment it is created.
Types of Constructors
There are three main types of constructors in C++:
1. Default Constructor
A constructor that takes no arguments (or has all default arguments). It is called automatically when an object is created without any parameters.
#include <iostream> using namespace std; class Student { private: int rollNo; float marks; public: // Default Constructor Student() { rollNo = 0; marks = 0.0; cout << "Default Constructor called!" << endl; } void display() { cout << "Roll No: " << rollNo << ", Marks: " << marks << endl; } }; int main() { Student s1; // Default constructor is called automatically s1.display(); return 0; }Output:
Default Constructor called! Roll No: 0, Marks: 0.0
2. Parameterized Constructor
A constructor that accepts one or more arguments to initialize data members with specific values at the time of object creation.
#include <iostream> using namespace std; class Student { private: int rollNo; float marks; public: // Parameterized Constructor Student(int r, float m) { rollNo = r; marks = m; cout << "Parameterized Constructor called!" << endl; } void display() { cout << "Roll No: " << rollNo << ", Marks: " << marks << endl; } }; int main() { Student s1(101, 85.5); // Parameterized constructor called Student s2(102, 90.0); s1.display(); s2.display(); return 0; }Output:
Parameterized Constructor called! Parameterized Constructor called! Roll No: 101, Marks: 85.5 Roll No: 102, Marks: 90.0
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 { private: int rollNo; float marks; public: // Parameterized Constructor Student(int r, float m) { rollNo = r; marks = m; } // Copy Constructor Student(const Student &s) { rollNo = s.rollNo; marks = s.marks; cout << "Copy Constructor called!" << endl; } void display() { cout << "Roll No: " << rollNo << ", Marks: " << marks << endl; } }; int main() { Student s1(101, 85.5); // Parameterized constructor Student s2(s1); // Copy constructor called s1.display(); s2.display(); return 0; }Output:
Copy Constructor called! Roll No: 101, Marks: 85.5 Roll No: 101, Marks: 85.5
Summary Table
Type Arguments Purpose Default Constructor None Initializes members with default values Parameterized Constructor One or more Initializes members with given values Copy Constructor Reference to same class object Creates a copy of an existing object
Note on Constructor vs Destructor
A class can have both a constructor and a destructor (
~classname()). While the constructor initializes/creates the object, the destructor cleans up (e.g., frees memory allocated bynew) when the object goes out of scope. Together they manage the full lifecycle of an object. - 310 marksFunctionsHideAnswer
When inline functions may not work? Define and write syntax for default arguments. Write a program to display N number of characters by using default arguments for both parameters. Assume that the function takes two arguments, one character to be printed and other how many times the character to be printed respectively.[10]
Answer: Inline Functions, Default Arguments, and Program
Part 1: When Inline Functions May NOT Work (3 marks)
The compiler may ignore the
inlinerequest and treat the function as a normal function in the following situations:-
Function contains loops - If the inline function contains looping statements such as
for,while, ordo-while, the compiler will not inline it. -
Function contains static variables - If the function has static local variables declared inside it, it cannot be inlined.
-
Function is recursive - A recursive inline function (a function that calls itself) cannot be expanded inline.
-
Function contains switch or goto statements - Functions containing
switchorgotocontrol statements may not be inlined. -
Function is too large/complex - If the function body is too large, inlining it would increase code size significantly, so the compiler refuses to inline it.
-
Function returns a value and contains multiple return statements - In some cases, multiple return points prevent inlining.
Note: The
inlinekeyword is only a request to the compiler, not a command. The compiler has the final decision.
Part 2: Default Arguments - Definition and Syntax (3 marks)
Definition:
A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function does not provide a value for that argument. It allows a function to be called with fewer arguments than it is defined to accept.
Key Rules:
- Default arguments must be specified from right to left (trailing arguments first).
- Once a default value is assigned to a parameter, all parameters to its right must also have default values.
- Default values are specified in the function declaration (prototype).
Syntax:
return_type function_name(datatype param1, datatype param2 = default_value);Example of syntax with two default arguments:
void display(char ch = '*', int n = 10);Here, if no arguments are passed,
chdefaults to'*'andndefaults to10.
Part 3: Program to Display N Number of Characters Using Default Arguments (4 marks)
#include <iostream> using namespace std; // Function declaration with default arguments // ch = character to print (default: '*') // n = number of times to print (default: 3) void printChar(char ch = '*', int n = 3); int main() { cout << "Using both default arguments (no arguments passed):" << endl; printChar(); // Output: *** cout << "\nUsing one argument (only character passed):" << endl; printChar('#'); // Output: ### cout << "\nUsing both arguments (no defaults used):" << endl; printChar('@', 7); // Output: @@@@@@@ cout << "\nUsing character '$' with 5 times:" << endl; printChar('$', 5); // Output: $$$$$ return 0; } // Function definition void printChar(char ch, int n) { cout << "Character: " << ch << " | Printed " << n << " time(s): "; for (int i = 1; i <= n; i++) { cout << ch; } cout << endl; }
Output:
Using both default arguments (no arguments passed): Character: * | Printed 3 time(s): *** Using one argument (only character passed): Character: # | Printed 3 time(s): ### Using both arguments (no defaults used): Character: @ | Printed 7 time(s): @@@@@@@ Using character '$' with 5 times: Character: $ | Printed 5 time(s): $$$$$
Explanation of the Program:
Function Call chusednusedSource printChar()'*'3Both defaults used printChar('#')'#'3ndefault usedprintChar('@', 7)'@'7No defaults used printChar('$', 5)'$'5No defaults used Important Note: Default arguments are written in the function declaration/prototype, not in the definition. The compiler substitutes the default value when the argument is omitted in the function call.
-
- 45 marksStream Class Hierarchy for Console Input/OHideAnswer
What do you mean by stream? Explain different stream class for file input/output. [5]
Stream and Stream Classes for File I/O in C++
What is a Stream?
A stream is a sequence of bytes flowing between a program and an input/output device (such as a file, keyboard, or screen). It acts as an abstraction layer between the program and the actual device.
- We have been using the
iostreamstandard library, which providescinandcoutfor reading from standard input and writing to standard output respectively. - For file-based I/O, C++ provides another standard library called
fstream, which defines specialized stream classes to read from and write to files.
To perform file processing in C++, the header file
<fstream>must be included in the source file.
Stream Classes for File Input/Output
The
fstreamlibrary defines three main data types (stream classes):
1.
ifstream(Input File Stream)- Represents the input file stream.
- Used to read information from files.
- Derived from
istream.
Example:
#include <fstream> using namespace std; int main() { ifstream fin; fin.open("data.txt"); // open file for reading char ch; while (fin >> ch) cout << ch; fin.close(); return 0; }
2.
ofstream(Output File Stream)- Represents the output file stream.
- Used to create files and write information to files.
- Derived from
ostream.
Example:
#include <fstream> using namespace std; int main() { ofstream fout; fout.open("data.txt"); // open file for writing fout << "Hello, File!"; fout.close(); return 0; }
3.
fstream(File Stream)- Represents the general file stream.
- Has the capabilities of both
ifstreamandofstream. - Can create files, write information to files, and read information from files.
Example:
#include <fstream> using namespace std; int main() { fstream file; file.open("data.txt", ios::in | ios::out); // read and write file << "Writing data"; file.close(); return 0; }
Summary Table
Class Purpose Operation ifstreamInput file stream Read from files ofstreamOutput file stream Create and write to files fstreamGeneral file stream Read and write to files
File Pointer Manipulation Functions
The stream classes also support functions to manage file pointer positions:
Function Description seekg()Moves the get (input) pointer to a specified location seekp()Moves the put (output) pointer to a specified location tellg()Returns the current position of the get pointer tellp()Returns the current position of the put pointer These functions allow random access within a file, enabling reading or writing at any desired position.
- We have been using the
- 55 marksStatic membersHideAnswer
Write a C++ program to display the number of objects created using static member. [5]
A static data member is shared by all objects of a class. It is initialized only once and retains its value throughout the program. It is used here to count how many objects have been created, because every time a constructor is called (...
- 65 marksFriend function and Static functionHideAnswer
Explain about friend function and friend class with an example. [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. - The declaration is placed inside the class body (in either private or public section) preceded by the ke...
- 75 marksConstructor and Destructor in derived clasHideAnswer
Describe the chain of constructors and destructors in inheritance. [5]
In inheritance, when an object of a derived class is created or destroyed, constructors and destructors of both the base class and the derived class are automatically invoked in a specific order. --- When a derived class object is create...
- 85 marksConcept of Virtual functionsHideAnswer
What is the use of reinterpret cast operator? Why do we need virtual function? [5]
Reinterpret Cast Operator and Virtual Functions
Part 1:
reinterpret_castOperatorDefinition
reinterpret_castis a cast operator in C++ that converts one pointer type to another pointer type, even if the types are unrelated. It forces the compiler to treat the bit pattern of one type as if it were another type entirely.As noted in the reference: "A cast operator is a special operator that forces one data type to be converted into another."
Syntax
reinterpret_cast<new_type>(expression);Uses of
reinterpret_castUse Case Description Pointer to pointer conversion Convert int*tochar*or any unrelated pointer typePointer to integer conversion Store a pointer value as an integer Integer to pointer conversion Convert an integer back to a pointer Low-level memory manipulation Used in hardware/system programming Example
#include <iostream> using namespace std; int main() { int a = 65; int* ptr = &a; // Reinterpret int pointer as char pointer char* cptr = reinterpret_cast<char*>(ptr); cout << "Integer value: " << *ptr << endl; cout << "Char interpretation: " << *cptr << endl; // Output: A return 0; }Key Points
- It does not check type safety; the programmer is responsible for correctness.
- It is the most dangerous cast and should be used with caution.
- Commonly used in low-level programming, such as device drivers or memory-mapped I/O.
Part 2: Why Do We Need Virtual Functions?
Problem Without Virtual Functions
When a base class pointer points to a derived class object, calling an overridden function without
virtualwill always call the base class version due to static (early) binding.From the reference: "When a member function is not virtual, the function called is determined only by the type of the expression to the left of dot (.) or arrow (->) operator. This is called the static type."
What is a Virtual Function?
A virtual function is a member function declared in the base class using the keyword
virtual, which tells the compiler to perform late binding (runtime binding) so that the correct overridden function is called based on the actual object type, not the pointer type.From the reference: "Late Binding is achieved using Virtual functions."
Example Demonstrating the Need
#include <iostream> using namespace std; class Base { public: virtual void print() { // virtual function cout << "Print Base class" << endl; } void show() { // non-virtual function cout << "Show Base class" << endl; } }; class Derived : public Base { public: void print() { cout << "Print Derived class" << endl; } void show() { cout << "Show Derived class" << endl; } }; int main() { Base* bptr; Derived d; bptr = &d; bptr->print(); // Virtual -> calls Derived version (runtime binding) bptr->show(); // Non-virtual -> calls Base version (compile-time binding) return 0; }Output
Print Derived class Show Base classWhy We Need Virtual Functions
- Runtime Polymorphism: Enables the correct function to be called based on the actual object at runtime, not the pointer type.
- Flexibility: A single base class pointer can manage objects of multiple derived classes and call appropriate methods.
- Extensibility: New derived classes can be added without changing existing code.
- Correct Overriding Behavior: Without
virtual, overriding does not work as expected through base class pointers.
Important Note
From the reference: "If we have created a virtual function in the base class and it is being overridden in the derived class, then we don't need the virtual keyword in the derived class -- functions are automatically considered as virtual functions in the derived class."
Summary Table
Feature reinterpret_castVirtual Function Purpose Low-level type conversion Runtime polymorphism Binding N/A Late (runtime) binding Safety Unsafe, programmer's responsibility Safe, resolved by vtable - 95 marksAbstract class and pure virtual functionsHideAnswer
Differentiate between concrete class and abstract class. Define class template and function template with syntax. [5]
--- As stated in the notes: "There are two main types of classes: Abstract class and Concrete class. The main difference between the two arises from the level of implementation of their method functionalities." Feature Concrete Class Abs...
- 105 marksExceptional HandlingHideAnswer
List any two operators that cannot be overloaded. Write a program to handle the possible exception in taking 'age' as input. Here the exception must be thrown in the input is negative or greater than 200. [5]
Answer
Two Operators That Cannot Be Overloaded
The following operators cannot be overloaded in C++:
Operator Name ::Scope Resolution Operator ?:Ternary (Conditional) Operator Other examples include:
.(member access),.*(pointer to member),sizeof.
Program to Handle Exception for Invalid Age Input
The program throws an exception if the entered age is negative or greater than 200.
#include <iostream> using namespace std; // Custom Exception Class for Age class AgeException { private: string message; public: AgeException(string msg) { message = msg; } string getMessage() { return message; } }; // Function to validate and return age int getAge(int age) { if (age < 0) { throw AgeException("Invalid age: Age cannot be negative."); } else if (age > 200) { throw AgeException("Invalid age: Age cannot be greater than 200."); } return age; } int main() { int age; cout << "Enter age: "; cin >> age; try { int validAge = getAge(age); cout << "Valid Age entered: " << validAge << endl; } catch (AgeException e) { cout << "Exception caught: " << e.getMessage() << endl; } return 0; }
Sample Output
Case 1: Valid Input
Enter age: 25 Valid Age entered: 25Case 2: Negative Age
Enter age: -5 Exception caught: Invalid age: Age cannot be negative.Case 3: Age Greater Than 200
Enter age: 250 Exception caught: Invalid age: Age cannot be greater than 200.
Explanation
- The
AgeExceptionclass is a user-defined exception class that stores an error message. - The
getAge()function throws anAgeExceptionobject when the age is invalid (negative or > 200). - In
main(), thetryblock callsgetAge()and thecatchblock handles the thrown exception by printing the error message. - This approach separates error-handling code from normal program code, which is one of the key uses of exception handling as stated in the notes.
- The
- 115 marksOperator functions as a class membersHideAnswer
Create a class named Point with data members x(int) and y(int). Add operator overloading to find the Euclidean distance between two points. [5]
Operator overloading allows us to redefine the behavior of an operator for user-defined types (classes). Here, we overload the - operator (or a suitable operator) to compute the Euclidean distance between two Point objects. The Euclidean...
- 125 marksConcept of Virtual functionsHideAnswer
Explain the reason for member function overriding when using virtual function. [5]
Member Function Overriding with Virtual Functions
Definition and Concept
Overriding means defining a member function with the same name in both the base class and the derived class. When such a function exists in both classes, the derived class function overrides the base class function.
Virtual function is a member function in the base class that is declared using the keyword
virtual. When virtual functions are used, different functions can be executed by the same function call statement.
Reason for Member Function Overriding When Using Virtual Functions
The Core Problem (Without Virtual)
When a base class pointer is used to point to a derived class object, without virtual, the function call is resolved at compile time (static binding). This means the base class version of the function always gets called, even when the pointer is pointing to a derived class object. This defeats the purpose of inheritance and polymorphism.
How Virtual Solves It
When a function is declared
virtualin the base class, the function call is resolved at runtime (dynamic binding). The function called is determined by the actual type of the object pointed to, not the type of the pointer.As per the notes: "When a member function is virtual, the function called is determined by the actual most derived type of the object named by the expression left of the dot or pointed to by the expression left of the arrow. This is called the dynamic type."
Types of Polymorphism Involved
Type How Achieved Binding Compile-time (Static) Overloading At compile time Runtime (Dynamic) Overriding with virtual At runtime
Example
#include <iostream> using namespace std; class base { public: virtual void print() { // virtual function cout << "Print base class" << endl; } void show() { // non-virtual function cout << "Show base class" << endl; } }; class derived : public base { public: void print() { // overrides base class print() cout << "Print derived class" << endl; } void show() { cout << "Show derived class" << endl; } }; int main() { base *bptr; derived d; bptr = &d; // base pointer pointing to derived object bptr->print(); // virtual function -> runtime binding bptr->show(); // non-virtual function -> compile-time binding return 0; }Output
Print derived class Show base class
Explanation of Output
bptr->print()calls the derived class version becauseprint()is declaredvirtualin the base class. The function is bound at runtime based on the actual object type (derived).bptr->show()calls the base class version becauseshow()is not virtual. It is bound at compile time based on the pointer type (base).
Key Points
- Runtime polymorphism is achieved only through a pointer or reference of a base class type.
- A base class pointer can point to objects of both base and derived classes.
- If a virtual function in the base class is overridden in the derived class, the
virtualkeyword is not required again in the derived class; the function is automatically considered virtual. - Without
virtual, member function overriding cannot achieve dynamic dispatch, making the concept of runtime polymorphism impossible.