Unit 1: OOAD, UML & Basic OOP
30. Differentiate between Data Abstraction and Data Hiding. [4 Marks]
Answer:
Both are fundamental concepts of OOP, but they serve entirely different purposes.
Both are fundamental concepts of OOP, but they serve entirely different purposes.
| Feature | Data Abstraction | Data Hiding |
|---|---|---|
| Definition | The process of identifying only the essential characteristics of an object while ignoring the irrelevant details. | The mechanism of restricting direct access to some of the object's components to prevent unauthorized modification. |
| Focus | Focuses on what the object does (observable behavior). | Focuses on how the object does it securely (internal mechanics). |
| Implementation | Achieved using Abstract Classes and Interfaces. | Achieved using Access Specifiers (`private`, `protected`). |
| Real-world Analogy | Knowing how to press the brake pedal to stop a car. | The internal hydraulic brake fluid system being enclosed and inaccessible to the driver. |
31. Explain Inline functions in C++ with a suitable example. What are its limitations? [8 Marks]
Answer:
An inline function is a function that is expanded "in-line" when it is called. When the inline function is called, the compiler replaces the function call with the actual code of the function. This is a compiler request, not a command.
Advantages:
1. Eliminates the overhead of a function call (no pushing/popping variables onto the stack).
2. Increases execution speed for small, frequently called functions.
Limitations / When Compiler ignores `inline`:
1. If the function contains a loop (`for`, `while`, `do-while`).
2. If the function contains `static` variables.
3. If the function is recursive.
4. If the function contains a `switch` or `goto` statement.
5. If the function return type is other than void, and the return statement doesn't exist.
An inline function is a function that is expanded "in-line" when it is called. When the inline function is called, the compiler replaces the function call with the actual code of the function. This is a compiler request, not a command.
Advantages:
1. Eliminates the overhead of a function call (no pushing/popping variables onto the stack).
2. Increases execution speed for small, frequently called functions.
Limitations / When Compiler ignores `inline`:
1. If the function contains a loop (`for`, `while`, `do-while`).
2. If the function contains `static` variables.
3. If the function is recursive.
4. If the function contains a `switch` or `goto` statement.
5. If the function return type is other than void, and the return statement doesn't exist.
#include <iostream>
using namespace std;
// Inline function definition
inline int square(int s) {
return s * s;
}
int main() {
cout << "Square of 5 is: " << square(5) << endl;
// At compile time, the above line is literally replaced by:
// cout << "Square of 5 is: " << (5 * 5) << endl;
return 0;
}
32. What is the significance of `static` data members and static member functions? [8 Marks]
Answer:
Properties of Static Data Members:
1. Class-wide Scope: Only one copy of that member is created for the entire class, and it is shared by all objects of that class.
2. Initialization: It is initialized to zero when the first object of its class is created, and it must be explicitly defined outside the class.
3. Memory: Memory is allocated in the static storage area, not within the individual object memory.
Properties of Static Member Functions:
1. A static function can only access static data members and other static functions. It cannot access non-static data.
2. It can be called using the class name and scope resolution operator `::` without creating an object (e.g., `Employee::showCount()`).
3. They do not have a `this` pointer.
Properties of Static Data Members:
1. Class-wide Scope: Only one copy of that member is created for the entire class, and it is shared by all objects of that class.
2. Initialization: It is initialized to zero when the first object of its class is created, and it must be explicitly defined outside the class.
3. Memory: Memory is allocated in the static storage area, not within the individual object memory.
Properties of Static Member Functions:
1. A static function can only access static data members and other static functions. It cannot access non-static data.
2. It can be called using the class name and scope resolution operator `::` without creating an object (e.g., `Employee::showCount()`).
3. They do not have a `this` pointer.
#include <iostream>
using namespace std;
class Employee {
public:
static int count; // Static Data Member Declaration
Employee() { count++; }
// Static Member Function
static void showCount() { cout << "Total Employees: " << count << endl; }
};
int Employee::count = 0; // Definition and Initialization outside class
int main() {
Employee e1;
Employee e2;
Employee::showCount(); // Output: 2. Called without object!
return 0;
}
33. Draw a UML Activity Diagram for an ATM Cash Withdrawal System. [8 Marks]
Answer:
An Activity diagram models the dynamic flow of control from one activity to another. It is essentially an advanced object-oriented flowchart.
Key Components of Activity Diagram:
- Initial Node: Solid black circle marking the start.
- Action Node: Rounded rectangles representing an operation/task.
- Decision Node: A diamond shape indicating branching based on a condition.
- Fork/Join Nodes: Thick black lines indicating splitting into parallel threads (Fork) and merging them back (Join).
- Final Node: Bullseye symbol marking the end.
Algorithm to Draw for ATM Withdrawal:
1. Start Node → Transition to Action `[Insert ATM Card]`.
2. Action `[Enter PIN]` → Transition to Decision Node.
3. Branch 1 (Invalid PIN): Transition to Action `[Eject Card]` → Final Node.
4. Branch 2 (Valid PIN): Transition to Action `[Enter Amount]` → Decision Node.
5. Branch 1 (Insufficient Balance): Transition to Action `[Show Error]` → `[Eject Card]` → Final Node.
6. Branch 2 (Sufficient Balance): Transition to Fork Node (Parallel Processing).
7. Parallel Actions from Fork: `[Dispense Cash]` AND `[Deduct Account Balance]`.
8. Both parallel actions transition into a Join Node.
9. Join Node → Action `[Print Receipt]` → Action `[Eject Card]` → Final Node.
An Activity diagram models the dynamic flow of control from one activity to another. It is essentially an advanced object-oriented flowchart.
Key Components of Activity Diagram:
- Initial Node: Solid black circle marking the start.
- Action Node: Rounded rectangles representing an operation/task.
- Decision Node: A diamond shape indicating branching based on a condition.
- Fork/Join Nodes: Thick black lines indicating splitting into parallel threads (Fork) and merging them back (Join).
- Final Node: Bullseye symbol marking the end.
Algorithm to Draw for ATM Withdrawal:
1. Start Node → Transition to Action `[Insert ATM Card]`.
2. Action `[Enter PIN]` → Transition to Decision Node.
3. Branch 1 (Invalid PIN): Transition to Action `[Eject Card]` → Final Node.
4. Branch 2 (Valid PIN): Transition to Action `[Enter Amount]` → Decision Node.
5. Branch 1 (Insufficient Balance): Transition to Action `[Show Error]` → `[Eject Card]` → Final Node.
6. Branch 2 (Sufficient Balance): Transition to Fork Node (Parallel Processing).
7. Parallel Actions from Fork: `[Dispense Cash]` AND `[Deduct Account Balance]`.
8. Both parallel actions transition into a Join Node.
9. Join Node → Action `[Print Receipt]` → Action `[Eject Card]` → Final Node.
Unit 2: Constructors, Overloading & Advanced UML
34. What is a Destructor? Can a destructor be overloaded? [4 Marks]
Answer:
A Destructor is a special member function that is automatically invoked when an object's scope ends or it is explicitly destroyed using the `delete` keyword. Its primary purpose is to deallocate memory and release resources acquired by the object during its lifetime.
Rules of a Destructor:
1. It has the same name as the class, preceded by a tilde (`~`). Example: `~Car()`.
2. It does not take any arguments.
3. It does not return any value (not even `void`).
Can it be overloaded?
No. Since a destructor takes no arguments, the compiler would have no way to distinguish between multiple destructors. A class can have exactly one destructor.
A Destructor is a special member function that is automatically invoked when an object's scope ends or it is explicitly destroyed using the `delete` keyword. Its primary purpose is to deallocate memory and release resources acquired by the object during its lifetime.
Rules of a Destructor:
1. It has the same name as the class, preceded by a tilde (`~`). Example: `~Car()`.
2. It does not take any arguments.
3. It does not return any value (not even `void`).
Can it be overloaded?
No. Since a destructor takes no arguments, the compiler would have no way to distinguish between multiple destructors. A class can have exactly one destructor.
35. Distinguish between Shallow Copy and Deep Copy. [8 Marks]
Answer:
When copying objects (especially those with dynamically allocated memory via pointers), the distinction between shallow and deep copy is critical.
When copying objects (especially those with dynamically allocated memory via pointers), the distinction between shallow and deep copy is critical.
| Feature | Shallow Copy | Deep Copy |
|---|---|---|
| Mechanism | Copies all member values verbatim. If a member is a pointer, only the memory address is copied. | Allocates entirely new memory for pointers, and copies the actual values pointed to by the original object. |
| Memory Sharing | Both the original and the copied object point to the same memory location. | The original and the copied object point to different, independent memory locations. |
| Data Corruption | Modifying the dynamic data of one object affects the other. If one object is destroyed, the other gets a dangling pointer. | Modifying one object does not affect the other. Safe destruction of objects. |
| Implementation | Provided by default by the C++ compiler's default copy constructor. | Requires the programmer to write a custom Copy Constructor explicitly. |
36. Write a C++ program to overload the `++` (increment) operator using a member function. [8 Marks]
Answer:
Operator overloading allows custom classes to use standard C++ operators. For the increment operator, we must overload both the prefix (`++obj`) and postfix (`obj++`) versions. The compiler distinguishes them by passing a dummy `int` parameter to the postfix version.
Operator overloading allows custom classes to use standard C++ operators. For the increment operator, we must overload both the prefix (`++obj`) and postfix (`obj++`) versions. The compiler distinguishes them by passing a dummy `int` parameter to the postfix version.
#include <iostream>
using namespace std;
class Counter {
private:
int count;
public:
Counter() { count = 0; }
// Overloading Prefix ++ (++obj)
void operator ++ () {
++count;
}
// Overloading Postfix ++ (obj++) using dummy 'int'
void operator ++ (int) {
count++;
}
void display() { cout << "Count: " << count << endl; }
};
int main() {
Counter c1;
++c1; // Invokes prefix operator
c1.display(); // Output: 1
c1++; // Invokes postfix operator
c1.display(); // Output: 2
return 0;
}
37. How to overload the insertion (`<<`) and extraction (`>>`) operators? [8 Marks]
Answer:
The `<<` (insertion) and `>>` (extraction) operators cannot be overloaded as member functions of our class because the left-hand operand is an `ostream` object (`cout`) or an `istream` object (`cin`), not an object of our class. Therefore, they must be overloaded as globally defined `friend` functions.
The `<<` (insertion) and `>>` (extraction) operators cannot be overloaded as member functions of our class because the left-hand operand is an `ostream` object (`cout`) or an `istream` object (`cin`), not an object of our class. Therefore, they must be overloaded as globally defined `friend` functions.
#include <iostream>
using namespace std;
class Person {
string name;
int age;
public:
// Declare friend functions
friend istream& operator >> (istream& in, Person& p);
friend ostream& operator << (ostream& out, const Person& p);
};
// Overload extraction operator
istream& operator >> (istream& in, Person& p) {
cout << "Enter name and age: ";
in >> p.name >> p.age;
return in;
}
// Overload insertion operator
ostream& operator << (ostream& out, const Person& p) {
out << "Name: " << p.name << ", Age: " << p.age;
return out;
}
int main() {
Person p1;
cin >> p1; // Calls operator>>
cout << p1 << endl; // Calls operator<<
return 0;
}
Unit 3: Inheritance, Polymorphism & Dynamic UML
38. What is the Diamond Problem in multiple inheritance? How is it resolved? [8 Marks]
Answer:
The Diamond Problem is an ambiguity that arises in Hybrid/Multiple Inheritance. If Class B and Class C both inherit from Class A, and Class D inherits from both B and C, then Class D ends up containing two duplicate copies of the members of Class A. When D tries to access a member of A, the compiler gets confused about which path (via B or via C) to resolve it, throwing an ambiguity error.
Resolution (Virtual Base Class):
It is resolved by making the inheritance from the grandparent class `A` virtual. This tells the compiler to only pass down a single, shared instance of Class A to the grandchild class D.
The Diamond Problem is an ambiguity that arises in Hybrid/Multiple Inheritance. If Class B and Class C both inherit from Class A, and Class D inherits from both B and C, then Class D ends up containing two duplicate copies of the members of Class A. When D tries to access a member of A, the compiler gets confused about which path (via B or via C) to resolve it, throwing an ambiguity error.
Resolution (Virtual Base Class):
It is resolved by making the inheritance from the grandparent class `A` virtual. This tells the compiler to only pass down a single, shared instance of Class A to the grandchild class D.
#include <iostream>
using namespace std;
class A { public: int a; };
class B : virtual public A { }; // Virtual Inheritance
class C : virtual public A { }; // Virtual Inheritance
class D : public B, public C { }; // D safely inherits from B and C
int main() {
D obj;
obj.a = 100; // No ambiguity error! Only ONE copy of 'a' exists.
cout << obj.a;
return 0;
}
39. What are Pure Virtual Functions and Abstract Classes? Explain with example. [8 Marks]
Answer:
- Pure Virtual Function: A virtual function declared in a base class that has no definition relative to the base class. It is declared by assigning `= 0`. It forces any derived class to provide its own implementation of this function.
- Abstract Class: A class that contains at least one pure virtual function is an Abstract Class. The primary rule of an abstract class is that you cannot create objects (instantiate) of an abstract class. It exists solely to act as a strict blueprint for derived classes.
- Pure Virtual Function: A virtual function declared in a base class that has no definition relative to the base class. It is declared by assigning `= 0`. It forces any derived class to provide its own implementation of this function.
- Abstract Class: A class that contains at least one pure virtual function is an Abstract Class. The primary rule of an abstract class is that you cannot create objects (instantiate) of an abstract class. It exists solely to act as a strict blueprint for derived classes.
#include <iostream>
using namespace std;
class Animal { // Abstract Class
public:
virtual void sound() = 0; // Pure Virtual Function
};
class Cat : public Animal {
public:
void sound() { cout << "Meow!" << endl; } // Implementation is mandatory
};
int main() {
// Animal a; // ERROR! Cannot instantiate an abstract class
Cat c;
c.sound(); // Valid
return 0;
}
40. Explain the concept of Pointer to Base Class pointing to Derived Class. [4 Marks]
Answer:
In C++, a pointer of type Base Class can legally hold the memory address of a Derived Class object. This is known as Upcasting.
1. It is the foundation of Runtime Polymorphism.
2. If the base class has a `virtual` function, calling that function via the base pointer will execute the derived class's version of the function, not the base class's version.
3. It allows us to create generic arrays (e.g., `Vehicle* arr[10];`) that can store pointers to Cars, Bikes, and Trucks all in one list.
In C++, a pointer of type Base Class can legally hold the memory address of a Derived Class object. This is known as Upcasting.
Base* ptr;
Derived obj;
ptr = &obj; // Valid: Base pointer points to Derived object
Why is this significant?1. It is the foundation of Runtime Polymorphism.
2. If the base class has a `virtual` function, calling that function via the base pointer will execute the derived class's version of the function, not the base class's version.
3. It allows us to create generic arrays (e.g., `Vehicle* arr[10];`) that can store pointers to Cars, Bikes, and Trucks all in one list.
41. Draw the State Chart Diagram for a Microwave Oven. [8 Marks]
Answer:
A State Chart Diagram models the dynamic behavior of a single object by showing its states, transitions, and the events that trigger those transitions.
Key UML Components Required:
- State: A rounded rectangle (e.g., `Idle`, `Heating`).
- Event/Trigger: The action that causes a change (e.g., `buttonPress`).
- Transition: Solid arrow connecting states.
- Entry/Exit Actions: Internal automatic actions upon entering/leaving a state.
Algorithm to Draw for Microwave:
1. Start Node (Black circle) → Transition to `[Idle]` state.
2. State 1: [Idle]
- Transition to `[Heating]` triggered by Event: `timerSet()` AND `startPressed()`.
3. State 2: [Heating]
- Internal Action: `entry / turnOnEmitter()`.
- Internal Action: `exit / turnOffEmitter()`.
- Transition to `[Paused]` triggered by Event: `openDoor()`.
- Transition back to `[Idle]` triggered by Event: `timerZero()`.
4. State 3: [Paused]
- Transition back to `[Heating]` triggered by Event: `closeDoor()` AND `startPressed()`.
5. Transition from `[Idle]` to Final Node (Bullseye) when unplugged.
A State Chart Diagram models the dynamic behavior of a single object by showing its states, transitions, and the events that trigger those transitions.
Key UML Components Required:
- State: A rounded rectangle (e.g., `Idle`, `Heating`).
- Event/Trigger: The action that causes a change (e.g., `buttonPress`).
- Transition: Solid arrow connecting states.
- Entry/Exit Actions: Internal automatic actions upon entering/leaving a state.
Algorithm to Draw for Microwave:
1. Start Node (Black circle) → Transition to `[Idle]` state.
2. State 1: [Idle]
- Transition to `[Heating]` triggered by Event: `timerSet()` AND `startPressed()`.
3. State 2: [Heating]
- Internal Action: `entry / turnOnEmitter()`.
- Internal Action: `exit / turnOffEmitter()`.
- Transition to `[Paused]` triggered by Event: `openDoor()`.
- Transition back to `[Idle]` triggered by Event: `timerZero()`.
4. State 3: [Paused]
- Transition back to `[Heating]` triggered by Event: `closeDoor()` AND `startPressed()`.
5. Transition from `[Idle]` to Final Node (Bullseye) when unplugged.
Unit 4: Templates, Exceptions & Structural UML
42. What is an Exception Specification? [4 Marks]
Answer:
An Exception Specification (also known as a throw list) is a declaration appended to a function signature that explicitly specifies the types of exceptions that the function is allowed to throw. It guarantees the caller that no other exception types will escape the function.
An Exception Specification (also known as a throw list) is a declaration appended to a function signature that explicitly specifies the types of exceptions that the function is allowed to throw. It guarantees the caller that no other exception types will escape the function.
void processData() throw(int, char) {
// This function is strictly restricted.
// It can only throw an 'int' or a 'char'.
// If it throws a 'float', the program terminates abnormally via std::unexpected().
}
Note: In modern C++ (C++11 and newer), dynamic exception specifications using `throw(...)` are deprecated. Developers now use the `noexcept` keyword to declare that a function guarantees not to throw any exceptions at all.
43. Differentiate between Function Templates and Overloaded Functions. [4 Marks]
Answer:
| Feature | Function Overloading | Function Templates |
|---|---|---|
| Definition | Creating multiple functions with the exact same name but different parameter lists. | Creating a single generic function that works with any data type. |
| Code Duplication | High. The programmer must manually write the function body multiple times. | None. The programmer writes the body once; the compiler generates the type-specific versions. |
| Use Case | Used when the logic/algorithm is different for different data types. | Used when the logic/algorithm is exactly the same for all data types (e.g., swapping two values). |
44. What is "Rethrowing an Exception"? Explain with example. [8 Marks]
Answer:
Rethrowing an exception occurs when a `catch` block catches an exception, performs some local processing (like logging the error), but determines it cannot completely handle or recover from the error. It then passes the exact same exception up the call stack to an outer `try-catch` block for final processing. This is done using the keyword `throw;` with absolutely no arguments.
Rethrowing an exception occurs when a `catch` block catches an exception, performs some local processing (like logging the error), but determines it cannot completely handle or recover from the error. It then passes the exact same exception up the call stack to an outer `try-catch` block for final processing. This is done using the keyword `throw;` with absolutely no arguments.
#include <iostream>
using namespace std;
void divide(int a, int b) {
try {
if (b == 0) throw 0;
cout << a / b << endl;
}
catch (int x) {
cout << "Inner Catch: Mathematical error logged in system." << endl;
throw; // Rethrowing the exception up to main()
}
}
int main() {
try {
divide(10, 0);
}
catch (...) {
cout << "Outer Catch: Showing 'Division by Zero' alert to User." << endl;
}
return 0;
}
45. Draw a UML Deployment Diagram for a Web Application. [8 Marks]
Answer:
A Deployment Diagram models the physical deployment of software artifacts onto hardware nodes. It shows how the software is installed on the physical infrastructure.
Key UML Components Required:
- Node: Represented as a 3D box. It represents a piece of hardware (e.g., Server, PC, Mobile).
- Artifact: Represented as a standard box inside a Node, usually with `<>`. It represents the software (e.g., database.jar, UI.html).
- Communication Path: Solid lines connecting Nodes, labeled with protocols (e.g., TCP/IP, HTTP).
Algorithm to Draw for Web App:
1. Draw a 3D box (Node). Label it `<> Client Computer`.
- Inside it, draw an Artifact box: `<> Web Browser`.
2. Draw a second 3D box (Node). Label it `<> Application Server`.
- Inside it, draw Artifact boxes: `<> Apache Web Server` and `<> Business Logic API`.
3. Draw a third 3D box (Node). Label it `<> Database Server`.
- Inside it, draw an Artifact box: `<> MySQL Database`.
4. Draw a solid line connecting `Client Computer` to `Application Server`. Label it `HTTP / TCP/IP`.
5. Draw a solid line connecting `Application Server` to `Database Server`. Label it `JDBC / TCP/IP`.
A Deployment Diagram models the physical deployment of software artifacts onto hardware nodes. It shows how the software is installed on the physical infrastructure.
Key UML Components Required:
- Node: Represented as a 3D box. It represents a piece of hardware (e.g., Server, PC, Mobile).
- Artifact: Represented as a standard box inside a Node, usually with `<
- Communication Path: Solid lines connecting Nodes, labeled with protocols (e.g., TCP/IP, HTTP).
Algorithm to Draw for Web App:
1. Draw a 3D box (Node). Label it `<
- Inside it, draw an Artifact box: `<
2. Draw a second 3D box (Node). Label it `<
- Inside it, draw Artifact boxes: `<
3. Draw a third 3D box (Node). Label it `<
- Inside it, draw an Artifact box: `<
4. Draw a solid line connecting `Client Computer` to `Application Server`. Label it `HTTP / TCP/IP`.
5. Draw a solid line connecting `Application Server` to `Database Server`. Label it `JDBC / TCP/IP`.
Unit 5: Standard Template Library (STL)
46. Difference between `std::vector` and `std::list`. When to use which? [8 Marks]
Answer:
When to use which?
- Use Vector as your default container. It is best when you need to read/access data frequently and add items mostly to the end.
- Use List when your algorithm requires massive amounts of insertion or deletion of elements in the middle of the dataset.
| Feature | std::vector | std::list |
|---|---|---|
| Internal Structure | Dynamic Array (Contiguous memory blocks). | Doubly-Linked List (Scattered memory nodes connected by pointers). |
| Random Access | Very Fast O(1). Can access elements directly via index (e.g., `v[5]`). | Not Allowed. Must traverse the list sequentially from the beginning O(N). |
| Insertion/Deletion (Middle) | Slow O(N). Requires shifting all subsequent elements in memory. | Very Fast O(1). Requires only pointer reassignment. No shifting. |
| Memory Overhead | Low. Stores only the data. | High. Stores data + two pointers (prev and next) per element. |
When to use which?
- Use Vector as your default container. It is best when you need to read/access data frequently and add items mostly to the end.
- Use List when your algorithm requires massive amounts of insertion or deletion of elements in the middle of the dataset.
47. What are Iterators in STL? Name the different types of Iterators. [8 Marks]
Answer:
Iterators are objects that point to elements inside an STL container. They act as a bridge between Containers and Algorithms, functioning very similarly to standard pointers. They allow algorithms to traverse and manipulate data structures without needing to understand the underlying physical memory layout of that container.
5 Categories of Iterators (Hierarchy from weakest to strongest):
1. Input Iterator: Read-only, moves forward only step-by-step.
2. Output Iterator: Write-only, moves forward only step-by-step.
3. Forward Iterator: Read/Write, moves forward only (used in `std::forward_list`).
4. Bidirectional Iterator: Read/Write, can move forward (`++`) and backward (`--`) step-by-step (used in `std::list`, `std::set`, `std::map`).
5. Random Access Iterator: The most powerful. Read/Write, can move forward/backward, AND can jump to any arbitrary element instantly using pointer arithmetic like `it + 5` (used natively in `std::vector` and `std::deque`).
Iterators are objects that point to elements inside an STL container. They act as a bridge between Containers and Algorithms, functioning very similarly to standard pointers. They allow algorithms to traverse and manipulate data structures without needing to understand the underlying physical memory layout of that container.
5 Categories of Iterators (Hierarchy from weakest to strongest):
1. Input Iterator: Read-only, moves forward only step-by-step.
2. Output Iterator: Write-only, moves forward only step-by-step.
3. Forward Iterator: Read/Write, moves forward only (used in `std::forward_list`).
4. Bidirectional Iterator: Read/Write, can move forward (`++`) and backward (`--`) step-by-step (used in `std::list`, `std::set`, `std::map`).
5. Random Access Iterator: The most powerful. Read/Write, can move forward/backward, AND can jump to any arbitrary element instantly using pointer arithmetic like `it + 5` (used natively in `std::vector` and `std::deque`).
48. What are Functors (Function Objects) in STL? Explain with an example. [8 Marks]
Answer:
A Functor (or Function Object) is a C++ class or struct that explicitly overloads the function call operator `operator()`. This allows an object instantiated from that class to be called and executed exactly as if it were an ordinary function.
Advantage over normal functions: Normal functions do not retain state. Functors are objects, meaning they can contain member variables to store data ("state") across multiple calls, making them incredibly powerful when passed into STL algorithms.
A Functor (or Function Object) is a C++ class or struct that explicitly overloads the function call operator `operator()`. This allows an object instantiated from that class to be called and executed exactly as if it were an ordinary function.
Advantage over normal functions: Normal functions do not retain state. Functors are objects, meaning they can contain member variables to store data ("state") across multiple calls, making them incredibly powerful when passed into STL algorithms.
#include <iostream>
using namespace std;
class Multiplier {
int factor; // State variable
public:
Multiplier(int f) { factor = f; }
// Overloading the function call () operator
int operator() (int num) {
return num * factor;
}
};
int main() {
Multiplier mObj(5); // Object initialized with a state of 5
// mObj is called exactly like a function!
cout << "Result: " << mObj(10); // Output: 50
return 0;
}
49. Write a C++ program to find the frequency of words in a given array of strings using `std::map`. [8 Marks]
Answer:
A `std::map` stores data in Key-Value pairs. For this problem, the word string acts as the unique Key, and its integer count acts as the Value.
A `std::map` stores data in Key-Value pairs. For this problem, the word string acts as the unique Key, and its integer count acts as the Value.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main() {
vector<string> words = {"apple", "banana", "apple", "cherry", "banana", "apple"};
// Map: Key is string (word), Value is int (frequency count)
map<string, int> freqMap;
// Counting frequencies
for (string w : words) {
// If 'w' doesn't exist, map inserts it with value 0, then increments it to 1.
// If it exists, it directly increments the existing value.
freqMap[w]++;
}
// Displaying results
cout << "Word Frequencies:" << endl;
// Iterating through the map
for (auto pair : freqMap) {
cout << pair.first << " : " << pair.second << endl;
}
return 0;
}