0% found this document useful (0 votes)
4 views

Cpp

Uploaded by

Gona viral
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Cpp

Uploaded by

Gona viral
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 55

UNIT 1

Concepts and Basics of C++ Programming


C++ is an object-oriented programming (OOP) language that provides a rich set of features for
handling data and performing various tasks. Below are some essential concepts and basics of C++
programming, explained with examples.

1. Reading and Writing Data using cin and cout


In C++, cin (character input) and cout (character output) are used to handle input and output
operations, respectively. cin is used to read input from the user, and cout is used to display output
on the screen.

Code Example:
#include <iostream>
using namespace std;

int main() {
int age;
cout << "Enter your age: ";
cin >> age; // Input from user
cout << "Your age is: " << age << endl; // Output to screen
return 0;
}

Explanation:
• cout displays the message to the user.
• cin takes the user’s input and stores it in the variable age.

2. Creating Classes and Class Objects


In C++, classes are blueprints for creating objects. A class defines the properties (data members)
and behaviors (member functions) of objects. To create an object of a class, you simply declare it by
its type.

Code Example:
#include <iostream>
using namespace std;

class Car {
public:
string model;
int year;

void displayDetails() {
cout << "Model: " << model << ", Year: " << year << endl;
}
};
int main() {
Car car1; // Creating an object of the class Car
car1.model = "Toyota";
car1.year = 2020;

car1.displayDetails(); // Accessing member function

return 0;
}

Explanation:
• Car is a class with two data members (model and year) and one member function
(displayDetails).
• car1 is an object of class Car.

3. Accessing Class Members


Class members (data members and member functions) can be accessed through objects. If a
member is public, it can be accessed directly; if private, it needs getters/setters.

Code Example:### **Functions in C++**

Functions are blocks of code that perform specific tasks in a C++ program. They help in
breaking down complex tasks into simpler, reusable parts. C++ provides various types of
functions such as functions with default parameters, inline functions, function overloading,
and recursion, among others.

---

## **1. Functions with Default Parameters/Arguments**

A function can have default values for its parameters. This allows you to call the function
without providing all the arguments. If arguments are omitted, the default values are used.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;
void greet(string name = "Guest", int age = 18) {
cout << "Hello " << name << ", Age: " << age << endl;
}

int main() {
greet(); // Uses default parameters
greet("Alice", 25); // Uses provided parameters
return 0;
}
```

**Explanation:**
- `greet` has default values for `name` and `age`.
- If the parameters are not provided during the function call, the default values are used.

---

## **2. Inline Functions**

An **inline function** is a function that is expanded in line at the point of call. It eliminates
the overhead of function calls by inserting the code of the function directly at the call site.
Inline functions are useful for small functions.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;

inline int add(int a, int b) {


return a + b;
}
int main() {
cout << "Sum: " << add(5, 10) << endl;
return 0;
}
```

**Explanation:**
- `add` is an inline function, and instead of calling the function, its code is inserted directly at
the point of call.

---

## **3. Manipulator Functions**

Manipulator functions are used to modify the state of output streams. Some common
manipulators in C++ are `setw`, `setprecision`, `endl`, and `flush`.

### **Code Example:**


```cpp
#include <iostream>
#include <iomanip> // For manipulators
using namespace std;

int main() {
double pi = 3.14159265359;

cout << "Without setw: " << pi << endl;


cout << "With setw(10): " << setw(10) << pi << endl; // Set width of 10
cout << "With setprecision(4): " << setprecision(4) << pi << endl; // Precision of 4
return 0;
}
```
**Explanation:**
- `setw(10)` sets the width of the printed output to 10 characters.
- `setprecision(4)` sets the precision of floating-point numbers to 4 digits.

---

## **4. Function Overloading and Scope Rules**

### **Function Overloading**


Function overloading occurs when two or more functions have the same name but differ in the
number or type of parameters.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;

void display(int a) {
cout << "Integer: " << a << endl;
}

void display(double a) {
cout << "Double: " << a << endl;
}

int main() {
display(5); // Calls display(int)
display(3.14); // Calls display(double)
return 0;
}
```
**Explanation:**
- Both `display` functions have the same name but different parameter types (int and double).

### **Scope Rules**


In C++, scope refers to the region where a variable or function can be accessed. There are
different types of scope:
- **Local Scope**: Inside a function.
- **Global Scope**: Outside all functions, accessible from anywhere in the program.
- **Class Scope**: Inside a class.

---

## **5. Friend of a Class (Friend Function and Friend Class)**

A **friend function** can access private and protected members of a class. Similarly, a
**friend class** can access the private and protected members of another class.

### **Code Example (Friend Function):**


```cpp
#include <iostream>
using namespace std;

class Box {
private:
int length;

public:
Box() : length(10) {}

// Friend function declaration


friend void printLength(Box b);
};

// Friend function definition


void printLength(Box b) {
cout << "Length: " << b.length << endl;
}

int main() {
Box box;
printLength(box); // Accessing private member through friend function
return 0;
}
```

**Explanation:**
- `printLength` is a friend function of `Box` and can access its private members.

### **Code Example (Friend Class):**


```cpp
#include <iostream>
using namespace std;

class Box {
private:
int length;

public:
Box() : length(10) {}

friend class BoxPrinter; // Declare BoxPrinter as a friend class


};
class BoxPrinter {
public:
void print(Box b) {
cout << "Length: " << b.length << endl; // Accessing private member
}
};

int main() {
Box box;
BoxPrinter printer;
printer.print(box); // Accessing private member through friend class
return 0;
}
```

**Explanation:**
- `BoxPrinter` is a friend class of `Box` and can access its private members.

---

## **6. Reference Variables**

A **reference variable** is an alias for another variable. Once a reference is initialized, it


cannot be changed to refer to a different variable.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;

int main() {
int x = 10;
int &ref = x; // Reference variable

cout << "x: " << x << endl;


cout << "ref: " << ref << endl;

ref = 20; // Modifying through reference


cout << "x after modifying ref: " << x << endl;
return 0;
}
```

**Explanation:**
- `ref` is a reference variable, referring to `x`.
- Modifying `ref` also changes the value of `x`.

---

## **7. Differences between Call by Value, Call by Address, and Call by Reference**

### **Call by Value**:


- The actual parameter is passed to the function.
- Changes made to the parameter inside the function do not affect the actual argument.

### **Call by Address**:


- The address of the argument is passed, allowing the function to modify the original variable.

### **Call by Reference**:


- A reference to the actual parameter is passed, allowing the function to directly modify the
original variable.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;

void byValue(int a) {
a = 20; // Modifies only local copy
}

void byAddress(int *a) {


*a = 30; // Modifies original value using address
}

void byReference(int &a) {


a = 40; // Modifies original value directly
}

int main() {
int x = 10;

byValue(x);
cout << "After byValue: " << x << endl; // x remains 10

byAddress(&x);
cout << "After byAddress: " << x << endl; // x becomes 30

byReference(x);
cout << "After byReference: " << x << endl; // x becomes 40

return 0;
}
```

**Explanation:**
- **Call by Value** does not affect the original variable.
- **Call by Address** and **Call by Reference** both modify the original variable.

---

## **8. Recursion (Function, Member Function)**

### **Recursion** occurs when a function calls itself. It is a powerful tool for solving
problems that can be broken down into smaller subproblems.

### **Code Example:**


```cpp
#include <iostream>
using namespace std;

int factorial(int n) {
if (n <= 1) return 1; // Base case
else return n * factorial(n - 1); // Recursive call
}

class Math {
public:
int fibonacci(int n) {
if (n <= 1) return n; // Base case
else return fibonacci(n - 1) + fibonacci(n - 2); // Recursive call
}
};

int main() {
int num = 5;
cout << "Factorial of " << num << ": " << factorial(num) << endl;
Math math;
cout << "Fibonacci of " << num << ": " << math.fibonacci(num) << endl;

return 0;
}
```

**Explanation:**
- The **`factorial`** function is a simple recursive function.
- The **`fibonacci`** function is a recursive member function of the `Math` class.

---

### **Summary Table**

| Concept | Description |
|----------------------------------|-----------------------------------------------------------------------------|
| **Default Parameters** | Functions with default values for parameters.
|
| **Inline Functions** | Functions expanded at the call site to eliminate function call
overhead. |
| **Function Overloading** | Functions with the same name but different parameters.
|
| **Friend Function/Class** | Functions/classes that can access private members of other
classes. |
| **Reference Variables** | Aliases for other variables. |
| **Call by Value, Address, Ref** | Different methods of passing arguments to functions.
|
| **Recursion** | Functions that call themselves to solve smaller
#include <iostream>
using namespace std;

class Person {
private:
string name;
public:
void setName(string n) {
name = n;
}
string getName() {
return name;
}
};

int main() {
Person person1;
person1.setName("John");
cout << "Name: " << person1.getName() << endl;
return 0;
}

Explanation:
• Private members are not directly accessible; we use public member functions (setName
and getName) to set and get the value.

4. Differences between Structures, Unions, Enumerations, and


Classes
Structures vs. Classes
• Structure: Used to group different types of data together. Members are by default public.
• Class: Also used to group data, but members are private by default, which means data
encapsulation can be enforced.

Unions
A union allows storing different types of data in the same memory location. Only one member of a
union can hold a value at a time.

Enumerations
An enumeration (enum) is a user-defined type consisting of a set of named integer constants.

Code Example:
#include <iostream>
using namespace std;

struct Student {
string name;
int age;
};

union Data {
int i;
float f;
char c;
};

enum Color { RED, GREEN, BLUE };


int main() {
Student student1 = {"Alice", 20};
cout << "Student Name: " << student1.name << ", Age: " << student1.age <<
endl;

Data data1;
data1.i = 5;
cout << "Union Data: " << data1.i << endl;

Color color = RED;


cout << "Color: " << color << endl; // Outputs 0 for RED
return 0;
}

Explanation:
• Student is a structure.
• Data is a union where only one of i, f, or c can be used at a time.
• Color is an enumeration.

5. Inline and Non-inline Member Functions


Inline Member Functions
An inline function is a function that is expanded in line when it is called. It reduces the overhead of
a function call. Inline functions are useful for small, frequently called functions.

Non-inline Member Functions


Non-inline functions are those that are not expanded in line. They are called normally, and a
function call is performed.

Code Example:
#include <iostream>
using namespace std;

class Rectangle {
public:
int width, height;

// Inline function
inline int area() {
return width * height;
}

// Non-inline function
int perimeter() {
return 2 * (width + height);
}
};

int main() {
Rectangle rect;
rect.width = 10;
rect.height = 5;
cout << "Area: " << rect.area() << endl;
cout << "Perimeter: " << rect.perimeter() << endl;
return 0;
}

Explanation:
• The area function is inline, meaning it will be expanded in the place where it is called.
• The perimeter function is a non-inline function.

6. Static Data Members and Static Member Functions


Static Data Members
Static data members are shared by all objects of the class. They are initialized only once and can be
accessed even without creating an object of the class.

Static Member Functions


Static member functions can only access static data members of the class. They cannot access non-
static members.

Code Example:
#include <iostream>
using namespace std;

class Counter {
public:
static int count; // Static data member

Counter() {
count++;
}

static void showCount() { // Static member function


cout << "Count: " << count << endl;
}
};

int Counter::count = 0; // Initialize static data member

int main() {
Counter c1, c2;
Counter::showCount(); // Accessing static member function
return 0;
}

Explanation:
• count is a static data member, shared by all instances of Counter.
• showCount is a static member function that can be called using the class name.
7. Differences between Procedural and Object-Oriented
Programming Paradigms
Procedural Programming
• Focuses on functions and procedures that operate on data.
• Code is structured into functions.
• Examples: C, Fortran.

Object-Oriented Programming (OOP)


• Focuses on objects, which combine data and functions.
• Supports concepts like classes, inheritance, polymorphism, encapsulation, and abstraction.
• Examples: C++, Java, Python.

Key Differences:
• Procedure vs. Object: Procedural programming focuses on actions (functions), whereas
OOP focuses on entities (objects).
• Data Encapsulation: OOP encapsulates data within objects, whereas in procedural
programming, data is often global or passed between functions.

8. Features of Input/Output Streams


C++ provides a rich set of features for input/output operations using streams. cin, cout, cerr,
and clog are the standard streams in C++ for handling input and output.

Code Example:
#include <iostream>
using namespace std;

int main() {
string name;
cout << "Enter your name: ";
getline(cin, name); // Read input with spaces
cout << "Hello, " << name << "!" << endl;

cerr << "This is an error message." << endl; // Used for error messages
clog << "This is a log message." << endl; // Used for logging

return 0;
}

Explanation:
• cin is used to get user input.
• cout is used to display output.
• cerr is used for error messages (outputs to the standard error stream).
• clog is used for logging information.
Summary Table
Concept Description
cin/cout Used for input/output operations.
Class and Object Classes define the structure of objects; objects are instances of classes.
Static Members Static data members and functions are shared among all objects of a class.
Inline Function Functions that are expanded inline to reduce overhead.
OOP focuses on objects, while procedural programming focuses on
OOP vs Procedural
functions.
I/O Streams Standard streams for input/output, such as cin, cout, cerr, and clog.

These concepts are foundational for understanding C++ and object-oriented programming (OOP).

Functions in C++
Functions are blocks of code that perform specific tasks in a C++ program. They help in breaking
down complex tasks into simpler, reusable parts. C++ provides various types of functions such as
functions with default parameters, inline functions, function overloading, and recursion, among
others.

1. Functions with Default Parameters/Arguments


A function can have default values for its parameters. This allows you to call the function without
providing all the arguments. If arguments are omitted, the default values are used.

Code Example:
#include <iostream>
using namespace std;

void greet(string name = "Guest", int age = 18) {


cout << "Hello " << name << ", Age: " << age << endl;
}

int main() {
greet(); // Uses default parameters
greet("Alice", 25); // Uses provided parameters
return 0;
}

Explanation:
• greet has default values for name and age.
• If the parameters are not provided during the function call, the default values are used.
2. Inline Functions
An inline function is a function that is expanded in line at the point of call. It eliminates the
overhead of function calls by inserting the code of the function directly at the call site. Inline
functions are useful for small functions.

Code Example:
#include <iostream>
using namespace std;

inline int add(int a, int b) {


return a + b;
}

int main() {
cout << "Sum: " << add(5, 10) << endl;
return 0;
}

Explanation:
• add is an inline function, and instead of calling the function, its code is inserted directly at
the point of call.

3. Manipulator Functions
Manipulator functions are used to modify the state of output streams. Some common manipulators
in C++ are setw, setprecision, endl, and flush.

Code Example:
#include <iostream>
#include <iomanip> // For manipulators
using namespace std;

int main() {
double pi = 3.14159265359;

cout << "Without setw: " << pi << endl;


cout << "With setw(10): " << setw(10) << pi << endl; // Set width of 10
cout << "With setprecision(4): " << setprecision(4) << pi << endl; //
Precision of 4
return 0;
}

Explanation:
• setw(10) sets the width of the printed output to 10 characters.
• setprecision(4) sets the precision of floating-point numbers to 4 digits.
4. Function Overloading and Scope Rules
Function Overloading
Function overloading occurs when two or more functions have the same name but differ in the
number or type of parameters.

Code Example:
#include <iostream>
using namespace std;

void display(int a) {
cout << "Integer: " << a << endl;
}

void display(double a) {
cout << "Double: " << a << endl;
}

int main() {
display(5); // Calls display(int)
display(3.14); // Calls display(double)
return 0;
}

Explanation:
• Both display functions have the same name but different parameter types (int and
double).

Scope Rules
In C++, scope refers to the region where a variable or function can be accessed. There are different
types of scope:
• Local Scope: Inside a function.
• Global Scope: Outside all functions, accessible from anywhere in the program.
• Class Scope: Inside a class.

5. Friend of a Class (Friend Function and Friend Class)


A friend function can access private and protected members of a class. Similarly, a friend class
can access the private and protected members of another class.

Code Example (Friend Function):


#include <iostream>
using namespace std;

class Box {
private:
int length;

public:
Box() : length(10) {}

// Friend function declaration


friend void printLength(Box b);
};

// Friend function definition


void printLength(Box b) {
cout << "Length: " << b.length << endl;
}

int main() {
Box box;
printLength(box); // Accessing private member through friend function
return 0;
}

Explanation:
• printLength is a friend function of Box and can access its private members.

Code Example (Friend Class):


#include <iostream>
using namespace std;

class Box {
private:
int length;

public:
Box() : length(10) {}

friend class BoxPrinter; // Declare BoxPrinter as a friend class


};

class BoxPrinter {
public:
void print(Box b) {
cout << "Length: " << b.length << endl; // Accessing private member
}
};

int main() {
Box box;
BoxPrinter printer;
printer.print(box); // Accessing private member through friend class
return 0;
}

Explanation:
• BoxPrinter is a friend class of Box and can access its private members.

6. Reference Variables
A reference variable is an alias for another variable. Once a reference is initialized, it cannot be
changed to refer to a different variable.
Code Example:
#include <iostream>
using namespace std;

int main() {
int x = 10;
int &ref = x; // Reference variable

cout << "x: " << x << endl;


cout << "ref: " << ref << endl;

ref = 20; // Modifying through reference


cout << "x after modifying ref: " << x << endl;
return 0;
}

Explanation:
• ref is a reference variable, referring to x.
• Modifying ref also changes the value of x.

7. Differences between Call by Value, Call by Address, and


Call by Reference
Call by Value:
• The actual parameter is passed to the function.
• Changes made to the parameter inside the function do not affect the actual argument.

Call by Address:
• The address of the argument is passed, allowing the function to modify the original variable.

Call by Reference:
• A reference to the actual parameter is passed, allowing the function to directly modify the
original variable.

Code Example:
#include <iostream>
using namespace std;

void byValue(int a) {
a = 20; // Modifies only local copy
}

void byAddress(int *a) {


*a = 30; // Modifies original value using address
}

void byReference(int &a) {


a = 40; // Modifies original value directly
}
int main() {
int x = 10;

byValue(x);
cout << "After byValue: " << x << endl; // x remains 10

byAddress(&x);
cout << "After byAddress: " << x << endl; // x becomes 30

byReference(x);
cout << "After byReference: " << x << endl; // x becomes 40

return 0;
}

Explanation:
• Call by Value does not affect the original variable.
• Call by Address and Call by Reference both modify the original variable.

8. Recursion (Function, Member Function)


Recursion occurs when a function calls itself. It is a powerful tool for solving
problems that can be broken down into smaller subproblems.

Code Example:
#include <iostream>
using namespace std;

int factorial(int n) {
if (n <= 1) return 1; // Base case
else return n * factorial(n - 1); // Recursive call
}

class Math {
public:
int fibonacci(int n) {
if (n <= 1) return n; // Base case
else return fibonacci(n - 1) + fibonacci(n - 2); // Recursive call
}
};

int main() {
int num = 5;
cout << "Factorial of " << num << ": " << factorial(num) << endl;

Math math;
cout << "Fibonacci of " << num << ": " << math.fibonacci(num) << endl;

return 0;
}

Explanation:
• The factorial function is a simple recursive function.
• The fibonacci function is a recursive member function of the Math class.
Summary Table
Concept Description
Default Parameters Functions with default values for parameters.
Functions expanded at the call site to eliminate function call
Inline Functions
overhead.
Function Overloading Functions with the same name but different parameters.
Friend Function/Class Functions/classes that can access private members of other classes.
Reference Variables Aliases for other variables.
Call by Value, Address, Ref Different methods of passing arguments to functions.
Recursion Functions that call themselves to solve smaller
UNIT 2
Pointers, Reference Variables, Arrays, and String Concepts in C++
In C++, pointers are variables that store memory addresses of other variables. Pointers provide a
powerful way to directly manipulate memory, but they also introduce potential problems such as
dangling pointers, wild pointers, and null pointer assignments. Understanding pointers and
reference variables is essential for managing dynamic memory, working with arrays, and handling
complex data structures such as objects.

1. Void Pointer
A void pointer is a special type of pointer that can point to any data type. It is a generic pointer, and
its type is not defined when it is declared. To dereference a void pointer, it must first be typecast
into another pointer type.

Code Example:
#include <iostream>
using namespace std;

void print(void* ptr, char type) {


if (type == 'i') {
cout << *(int*)ptr << endl; // Cast to int pointer and dereference
}
else if (type == 'f') {
cout << *(float*)ptr << endl; // Cast to float pointer and dereference
}
}

int main() {
int x = 10;
float y = 5.5;

void* ptr = &x;


print(ptr, 'i'); // Prints the integer

ptr = &y;
print(ptr, 'f'); // Prints the float

return 0;
}

Explanation:
• void* is used as a pointer to any data type.
• The type of the data is identified by the type parameter, and then the pointer is typecasted
before dereferencing.

2. Pointer Arithmetic
Pointer arithmetic allows you to perform operations on pointers, such as incrementing or
decrementing them, and accessing memory locations at a specific offset.
Code Example:
#include <iostream>
using namespace std;

int main() {
int arr[] = {10, 20, 30, 40};
int* ptr = arr;

cout << "Pointer arithmetic:" << endl;


cout << *ptr << endl; // Output: 10
ptr++; // Move the pointer to the next element
cout << *ptr << endl; // Output: 20

ptr += 2; // Move the pointer two positions ahead


cout << *ptr << endl; // Output: 30

return 0;
}

Explanation:
• Pointer arithmetic is used to navigate through an array. ptr++ increments the pointer,
moving to the next array element.

3. Pointer to Pointer
A pointer to a pointer is a pointer that stores the address of another pointer. This is used when
dealing with dynamic memory allocation or multi-level data structures.

Code Example:
#include <iostream>
using namespace std;

int main() {
int num = 10;
int* ptr = &num; // Pointer to integer
int** ptr2 = &ptr; // Pointer to pointer

cout << "Value of num: " << num << endl;


cout << "Value using ptr: " << *ptr << endl;
cout << "Value using ptr2: " << **ptr2 << endl; // Dereferencing twice

return 0;
}

Explanation:
• ptr is a pointer to an integer, and ptr2 is a pointer to a pointer to an integer.
• **ptr2 accesses the value of num by dereferencing twice.

4. Possible Problems with Pointers


Pointers can lead to several issues if not managed carefully, including:
Dangling Pointer
A dangling pointer is a pointer that points to a memory location that has been freed or deallocated.
Using such pointers can lead to undefined behavior.

Wild Pointer
A wild pointer is an uninitialized pointer that points to some arbitrary memory location.

Null Pointer Assignment


A null pointer points to no valid memory location. Assigning a null pointer to an uninitialized
pointer avoids wild pointer issues.

Code Example (Dangling and Wild Pointer):


#include <iostream>
using namespace std;

int* createArray() {
int* arr = new int[5]; // Dynamically allocated memory
return arr;
}

int main() {
int* ptr = createArray();
delete[] ptr; // Deallocating memory
cout << *ptr << endl; // Dereferencing a dangling pointer - Undefined
behavior

int* wildPtr; // Uninitialized pointer (wild pointer)


cout << *wildPtr << endl; // Dereferencing a wild pointer - Undefined
behavior

return 0;
}

Explanation:
• ptr becomes a dangling pointer after memory is deallocated using delete[].
• wildPtr is uninitialized, leading to undefined behavior when dereferenced.

5. Classes Containing Pointers


A class can contain pointers, which can be used to dynamically allocate memory for its members.
It's important to manage the memory properly to avoid memory leaks.

Code Example:
#include <iostream>
using namespace std;

class MyClass {
private:
int* ptr;

public:
MyClass(int val) {
ptr = new int(val); // Dynamically allocating memory
}

~MyClass() {
delete ptr; // Deallocating memory in the destructor
}

void display() {
cout << "Value: " << *ptr << endl;
}
};

int main() {
MyClass obj(100);
obj.display();
return 0;
}

Explanation:
• MyClass contains a pointer ptr, and memory is dynamically allocated in the constructor.
The memory is freed in the destructor to prevent memory leaks.

6. Pointer to Objects
A pointer to an object is used to point to an instance of a class. This allows for dynamic memory
allocation and can be useful when working with arrays of objects or when passing objects to
functions.

Code Example:
#include <iostream>
using namespace std;

class Box {
public:
int length;

Box(int len) : length(len) {}


};

int main() {
Box* ptr = new Box(10); // Dynamically creating a Box object
cout << "Box length: " << ptr->length << endl;
delete ptr; // Deallocating memory
return 0;
}

Explanation:
• ptr is a pointer to an object of class Box, and it points to a dynamically allocated object.
The object is deleted after use.
7. The this Pointer
The this pointer is an implicit pointer available to all non-static member functions of a class. It
points to the object that is currently calling the function.

Code Example:
#include <iostream>
using namespace std;

class Box {
public:
int length;

Box(int len) : length(len) {}

void display() {
cout << "Length: " << this->length << endl; // Using this pointer
}
};

int main() {
Box box(5);
box.display();
return 0;
}

Explanation:
• The this pointer is used to refer to the current object. It is often used to differentiate
between local variables and member variables.

8. Array of Objects
An array of objects is an array where each element is an instance of a class. This is useful when you
need to store multiple objects of the same class.

Code Example:
#include <iostream>
using namespace std;

class Box {
public:
int length;

Box(int len) : length(len) {}

void display() {
cout << "Length: " << length << endl;
}
};

int main() {
Box boxes[3] = {Box(5), Box(10), Box(15)}; // Array of objects

for (int i = 0; i < 3; i++) {


boxes[i].display();
}

return 0;
}

Explanation:
• boxes is an array of Box objects, and the display() function is called for each object in
the array.

9. The Standard C++ String Class


The string class in C++ provides an easy way to handle strings of characters. It is part of the C+
+ Standard Library and supports various operations such as concatenation, comparison, and
modification.

Code Example (String Class):


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

int main() {
string str1 = "Hello";
string str2 = "World";

string result = str1 + " " + str2; // Concatenation


cout << "Concatenated String: " << result << endl;

cout << "Length of the string: " << result.length() << endl;
return 0;
}

Explanation:
• The string class handles dynamic memory management for strings automatically. You
can use operators like + to concatenate strings.

10. Differences between Pointer and Reference Variables


• A pointer holds the memory address of a variable, whereas a reference variable is an alias
for an existing variable.
• A pointer can be null, but a reference must always refer to a valid object.

11. Array Declaration and Processing of Multidimensional Arrays


In C++, multidimensional arrays are arrays of arrays. These arrays can be
processed either inside the main function or within a class.
Code Example (Multidimensional Array):
#include <iostream>
using namespace std;

class Matrix {
public:
void display(int arr[2][2]) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
}
};

int main() {
int mat[2][2] = {{1, 2}, {3, 4}};
Matrix obj;
obj.display(mat);
return 0;
}

Explanation:
• The class Matrix has a member function display that takes a 2D array and prints its
elements.

12. Pointer to Data Member


A pointer to data member allows you to access a member variable of a class through a pointer.

Code Example:
#include <iostream>
using namespace std;

class Box {
public:
int length;

Box(int len) : length(len) {}


};

int main() {
Box box(10);
int Box::*ptr = &Box::length; // Pointer to data member

cout << "Length: " << box.*ptr << endl; // Accessing data member through
pointer

return 0;
}

Explanation:
• ptr is a pointer to the length data member of the Box class.
• The .* operator is used to access the data member using the pointer.
Summary Table
Concept Description
Void Pointer A pointer that can point to any data type.
Operations like increment and decrement on pointers to access
Pointer Arithmetic
memory.
Pointer to Pointer A pointer that stores the address of another pointer.
Possible Pointer Problems Dangling pointer, wild pointer, null pointer assignment.
Classes Containing Classes can contain pointers to dynamically allocate and free
Pointers memory.
Pointer to Objects A pointer that points to an instance of a class.
A pointer available in non-static member functions that points to the
This Pointer
object.
Array of Objects An array where each element is an instance of a class.
Standard C++ String Class Class for handling strings with built-in functions for manipulation.
Pointer vs Reference Pointers hold memory addresses; references are aliases for variables.
Multidimensional Arrays Arrays of arrays, processed inside functions or classes.
Pointer to Data Member A pointer that points to a specific data member of a class.
UNIT 3

Data File Operations in C++


File handling in C++ allows reading and writing data to external files, enabling persistent storage of
information. The C++ Standard Library provides classes like fstream, ifstream, and
ofstream to perform file operations. There are two main types of file processing: sequential
access and random access.

1. Opening and Closing Files


To work with files, you first need to open them, perform operations like reading or writing, and
then close the file when done. The file must be opened in a specific mode to allow operations like
reading, writing, or appending.

2. Modes of File
Here are the common file opening modes:
• ios::in: Open for input (reading).
• ios::out: Open for output (writing).
• ios::app: Open for appending (writing at the end of the file).
• ios::binary: Open in binary mode (default is text mode).
• ios::trunc: Open and truncate the file to zero length (default when opening for writing).

3. File Stream Functions


• open(): Opens the file.
• close(): Closes the file.
• read(): Reads data from the file.
• write(): Writes data to the file.
• eof(): Checks if the end of the file is reached.
• getline(): Reads a line from the file.

Code Example: File Operations (Opening, Writing, Reading, Closing)


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

int main() {
// Writing to a file
ofstream outFile("example.txt", ios::out);
if (!outFile) {
cout << "Error opening file for writing!" << endl;
return 1;
}
outFile << "Hello, File Handling in C++!" << endl;
outFile.close(); // Close the file after writing

// Reading from a file


ifstream inFile("example.txt", ios::in);
if (!inFile) {
cout << "Error opening file for reading!" << endl;
return 1;
}
string line;
while (getline(inFile, line)) {
cout << line << endl; // Display the content of the file
}
inFile.close(); // Close the file after reading

return 0;
}

Explanation:
• ofstream is used for writing to files.
• ifstream is used for reading from files.
• Files are opened in ios::out and ios::in modes, respectively.
• After operations, files are closed with the close() function.

4. Sequential Access and Random Access File Processing


• Sequential Access: Data is read or written one record after another. It is the most common
method used for text files.
• Random Access: Allows reading and writing data at any position within the file using
seekg() (for get) and seekp() (for put) to move the file pointer.

Random Access Example:


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

int main() {
// Open a binary file for random access
fstream file("example.bin", ios::in | ios::out | ios::binary);
if (!file) {
cout << "Error opening file!" << endl;
return 1;
}

// Move to the 5th byte in the file


file.seekg(5, ios::beg);
char ch;
file.get(ch); // Read the character at the 5th position
cout << "Character at position 5: " << ch << endl;

// Writing at a specific location


file.seekp(10, ios::beg);
file.put('X'); // Write 'X' at the 10th byte

file.close(); // Close the file


return 0;
}

Explanation:
• seekg(): Moves the get pointer (reading position).
• seekp(): Moves the put pointer (writing position).
• File is opened in binary mode (ios::binary) for random access.

5. Binary File Operations


Binary files store data in a format that is not human-readable and are used to store data more
efficiently. C++ supports binary file operations using fstream with the ios::binary mode.

Binary File Example:


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

struct Employee {
int id;
char name[20];
};

int main() {
// Writing to binary file
Employee emp = {101, "John Doe"};
ofstream outFile("employee.dat", ios::binary);
if (!outFile) {
cout << "Error opening file!" << endl;
return 1;
}
outFile.write(reinterpret_cast<char*>(&emp), sizeof(emp));
outFile.close();

// Reading from binary file


Employee empRead;
ifstream inFile("employee.dat", ios::binary);
if (!inFile) {
cout << "Error opening file!" << endl;
return 1;
}
inFile.read(reinterpret_cast<char*>(&empRead), sizeof(empRead));
cout << "Employee ID: " << empRead.id << ", Name: " << empRead.name << endl;
inFile.close();

return 0;
}

Explanation:
• reinterpret_cast<char*> is used to convert the address of a structure into a pointer
to a char for binary writing and reading.
• The file is opened in binary mode using ios::binary.

6. Classes and File Operations


Classes can be used in file handling to encapsulate operations like reading from and writing to files.
Below is an example of using a class to manage file operations.
Class and File Operation Example:
#include <iostream>
#include <fstream>
using namespace std;

class Student {
private:
int rollNo;
string name;

public:
void setData(int r, const string& n) {
rollNo = r;
name = n;
}

void display() {
cout << "Roll No: " << rollNo << ", Name: " << name << endl;
}

void writeToFile() {
ofstream outFile("student.txt", ios::out);
if (outFile) {
outFile << rollNo << endl;
outFile << name << endl;
}
}

void readFromFile() {
ifstream inFile("student.txt", ios::in);
if (inFile) {
inFile >> rollNo;
inFile.ignore();
getline(inFile, name);
}
}
};

int main() {
Student s1;
s1.setData(101, "Alice");
s1.writeToFile();

Student s2;
s2.readFromFile();
s2.display();

return 0;
}

Explanation:
• The Student class has member functions to write to and read from a file.
• The writeToFile method writes the student's data to a file, while readFromFile
reads data from the file into the object's attributes.
7. Structures and File Operations
You can also use structures to perform file operations. A structure allows you to group different
types of data and is useful when working with records.

Structure and File Operation Example:


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

struct Product {
int id;
char name[20];
};

int main() {
Product prod = {101, "Laptop"};

// Writing to binary file


ofstream outFile("product.dat", ios::binary);
outFile.write(reinterpret_cast<char*>(&prod), sizeof(prod));
outFile.close();

// Reading from binary file


Product prodRead;
ifstream inFile("product.dat", ios::binary);
inFile.read(reinterpret_cast<char*>(&prodRead), sizeof(prodRead));
cout << "Product ID: " << prodRead.id << ", Name: " << prodRead.name <<
endl;
inFile.close();

return 0;
}

Explanation:
• Product structure is used to store data.
• reinterpret_cast<char*> is used for binary file operations.

Constructors, Destructors, and File Handling


1. Constructors and Destructors
Constructors are special member functions used for initialization of objects. Destructors are used to
free resources when an object is destroyed.
• Default Constructor: Initializes objects with default values.
• Parameterized Constructor: Initializes objects with specific values.
• Copy Constructor: Creates a copy of an object.
• Destructor: Cleans up resources when an object goes out of scope.

2. Manager Functions Example (File Handling with Constructors and Destructors)


#include <iostream>
#include <fstream>
using namespace std;
class FileManager {
public:
ofstream outFile;
ifstream inFile;

// Constructor to open file for writing


FileManager() {
outFile.open("data.txt", ios::out);
if (!out

File) { cout << "Error opening file!" << endl; exit(1); } }


// Destructor to close file
~FileManager() {
outFile.close();
cout << "File closed!" << endl;
}

void writeData() {
outFile << "Data written using constructor and destructor!" << endl;
}

};
int main() { FileManager fileManager; fileManager.writeData(); return 0; }

**Explanation:**
- The `FileManager` class has a constructor to open the file for writing and a
destructor to close it automatically when the object is destroyed.

Summary of Concepts:
Concept Description
File Opening & Closing Use open() and close() to manage files.
File Modes Define file access mode: read, write, append, binary.
Sequential vs Random Sequential: Data is processed in order; Random: Data accessed at any
Access position.
Binary File Operations Reading/writing data in binary format using ios::binary .
Classes & File Handling Encapsulate file operations in classes for better structure.
Structures & File Use structures to manage record-like data when performing file
Operations operations.
Constructors &
Automate initialization and cleanup with constructors and destructo
Destructors
UNIT 4

Operator Overloading and Type Conversion in C++


1. Operator Overloading:
Operator overloading allows you to define custom behavior for operators (such as +, -, *, etc.)
when they are used with user-defined types (like classes or structures). You can overload both
unary operators (which operate on a single operand) and binary operators (which operate on two
operands).

Unary Operator Overloading:


A unary operator operates on a single operand. You can overload it by defining a function with a
specific signature, using the operator keyword.

Example: Unary Operator Overloading


#include <iostream>
using namespace std;

class Complex {
public:
int real, imag;

// Constructor to initialize the complex number


Complex(int r = 0, int i = 0) : real(r), imag(i) {}

// Overloading the unary negation operator (-)


Complex operator-() {
return Complex(-real, -imag);
}

void display() {
cout << "Complex Number: " << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(4, 5);
Complex c2 = -c1; // Using overloaded unary operator
c2.display(); // Output: Complex Number: -4 + -5i
return 0;
}

Explanation:
• The operator-() function overloads the negation (-) operator for the Complex class. It
negates both the real and imaginary parts of the complex number.

Binary Operator Overloading:


Binary operators operate on two operands. These can be overloaded in a similar way to unary
operators, but the function takes two arguments: one for the left operand and one for the right
operand.
Example: Binary Operator Overloading
#include <iostream>
using namespace std;

class Complex {
public:
int real, imag;

// Constructor to initialize the complex number


Complex(int r = 0, int i = 0) : real(r), imag(i) {}

// Overloading the binary plus operator (+)


Complex operator+(Complex const &other) {
return Complex(real + other.real, imag + other.imag);
}

void display() {
cout << "Complex Number: " << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(4, 5), c2(1, 2);
Complex c3 = c1 + c2; // Using overloaded binary operator
c3.display(); // Output: Complex Number: 5 + 7i
return 0;
}

Explanation:
• The operator+() function overloads the addition (+) operator for the Complex class. It
adds the real and imaginary parts of two Complex objects.

2. Type Conversion in C++


Type conversion allows you to convert data from one type to another, whether it’s from basic data
types to user-defined types (like classes), or the reverse. There are two main types of type
conversions in C++:

Basic Type to Class Type Conversion (Implicit and Explicit)


Implicit Conversion:
Implicit conversion occurs automatically when you assign a basic type (like int) to a class type
(like Complex).

Explicit Conversion:
Explicit conversion is done by defining a constructor or conversion operator in the class.

Example: Implicit and Explicit Conversion


#include <iostream>
using namespace std;

class Complex {
public:
int real, imag;
// Constructor to initialize Complex from an int
Complex(int r) : real(r), imag(0) {}

// Constructor to initialize Complex from two ints


Complex(int r, int i) : real(r), imag(i) {}

void display() {
cout << "Complex Number: " << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1 = 5; // Implicit conversion from int to Complex (calls
Complex(int))
c1.display(); // Output: Complex Number: 5 + 0i

Complex c2 = Complex(3, 4); // Explicit conversion


c2.display(); // Output: Complex Number: 3 + 4i

return 0;
}

Explanation:
• The implicit conversion is achieved by the constructor Complex(int r), which allows
an int to be directly assigned to a Complex object.
• The explicit conversion is done by passing two arguments to the Complex constructor.

Class Type to Basic Type Conversion


This can be done by defining a conversion operator inside the class.

Example: Class Type to Basic Type Conversion


#include <iostream>
using namespace std;

class Complex {
public:
int real, imag;

Complex(int r = 0, int i = 0) : real(r), imag(i) {}

// Conversion operator to convert Complex to int (real part)


operator int() {
return real;
}

void display() {
cout << "Complex Number: " << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c(5, 7);
int x = c; // Calls the conversion operator
cout << "Real part as int: " << x << endl; // Output: Real part as int: 5
return 0;
}

Explanation:
• The operator int() function is a conversion operator that converts a Complex
object to an int by returning the real part.

Inheritance in C++
Inheritance allows one class (the derived class) to inherit the properties and methods of another
class (the base class). Inheritance promotes code reuse and creates a hierarchy of classes.

Types of Inheritance:
• Single Inheritance: A class inherits from only one base class.
• Multilevel Inheritance: A class inherits from a class that is already derived from another
class.
• Multiple Inheritance: A class inherits from more than one base class.
• Hierarchical Inheritance: Multiple classes inherit from a single base class.

Modes of Inheritance:
• Private: The members of the base class are inherited as private in the derived class.
• Protected: The members of the base class are inherited as protected in the derived class.
• Public: The members of the base class are inherited as public in the derived class.

Example: Basic Inheritance


#include <iostream>
using namespace std;

class Base {
public:
void displayBase() {
cout << "This is the base class" << endl;
}
};

class Derived : public Base { // Public inheritance


public:
void displayDerived() {
cout << "This is the derived class" << endl;
}
};

int main() {
Derived obj;
obj.displayBase(); // Access base class method
obj.displayDerived(); // Access derived class method
return 0;
}

Explanation:
• The derived class Derived inherits from the base class Base using public inheritance.
This allows the derived class to access the public methods of the base class.
Order of Execution of Constructors and Destructors
• The constructor of the base class is called before the constructor of the derived class.
• The destructor of the derived class is called before the destructor of the base class.

Example: Constructor and Destructor Order


#include <iostream>
using namespace std;

class Base {
public:
Base() {
cout << "Base class constructor" << endl;
}

~Base() {
cout << "Base class destructor" << endl;
}
};

class Derived : public Base {


public:
Derived() {
cout << "Derived class constructor" << endl;
}

~Derived() {
cout << "Derived class destructor" << endl;
}
};

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

Output:
Base class constructor
Derived class constructor
Derived class destructor
Base class destructor

Explanation:
• The Base class constructor is called first, followed by the Derived class constructor.
• When the object is destroyed, the Derived class destructor is called first, followed by the
Base class destructor.

Virtual Base Class and Resolving Ambiguities


A virtual base class is used to solve issues that arise in diamond inheritance (where two classes
inherit from a common base class and another class inherits from both).

Example: Virtual Base Class


#include <iostream>
using namespace std;
class Base {
public:
virtual void display() {
cout << "Base class" << endl;
}
};

class Derived1 : virtual public Base {


public:
void display() override {
cout << "Derived1 class" << endl;
}
};

class Derived2 : virtual public Base {


public:
void display() override {
cout << "Derived2 class" << endl;
}
};

class Final : public Derived1, public Derived2 {


public:
void display() override {
cout << "Final class" << endl;
}
};

int main() {
Final obj;
obj.display(); // Output:

Final class return 0; }


**Explanation:**
- `Derived1` and `Derived2` both virtually inherit from `Base`. This ensures
that there is only one instance of the `Base` class, resolving ambiguities.

---

Concept Description
Operator Allows defining custom behavior for operators (+, -, etc.) in user-defined
Overloading types.
Unary Operator Operates on one operand (e.g., negation operator - ).
Binary Operator Operates on two operands (e.g., addition operator + ).
Converting between basic types and class types using constructors and
Type Conversion
operators.
A mechanism to derive a new class from an existing class, supporting code
Inheritance
reuse.
Types of Inheritance Single, multilevel, multiple, and hierarchical inheritance.
Private, protected, and public inheritance control access to inherited
Modes of Inheritance
members.
Virtual Base Class Resolves ambiguities in diamond inheritance.
UNIT 5

Dynamic Memory Management and Polymorphism in C++

1. Dynamic Memory Allocation using new and delete Operators


Dynamic memory allocation in C++ allows you to allocate memory at runtime using the new
operator and deallocate it using the delete operator. This is useful when the size of the data
cannot be determined at compile time.
• new operator: Allocates memory for a variable or an array on the heap.
• delete operator: Frees dynamically allocated memory.

Example: Using new and delete


#include <iostream>
using namespace std;

int main() {
int *ptr = new int; // dynamically allocating memory for an integer
*ptr = 10; // assigning a value to the allocated memory

cout << "Value: " << *ptr << endl; // Output: Value: 10

delete ptr; // deallocating the memory


return 0;
}

Explanation:
• new int allocates memory for an integer on the heap, and delete ptr frees the
allocated memory.
• Using new[] and delete[] can be used for arrays.

Example: Dynamic Array Allocation


#include <iostream>
using namespace std;

int main() {
int n = 5;
int *arr = new int[n]; // dynamically allocating an array of 5 integers

for (int i = 0; i < n; i++) {


arr[i] = i + 1; // initializing the array
}

for (int i = 0; i < n; i++) {


cout << arr[i] << " "; // Output: 1 2 3 4 5
}

delete[] arr; // deallocating the memory for the array


return 0;
}
2. Virtual Destructors
A virtual destructor ensures that the correct destructor is called when a derived class object is
deleted through a base class pointer. Without a virtual destructor, the destructor of the base class
will be called, and the derived class's destructor will not be invoked, leading to resource leaks.

Example: Virtual Destructor


#include <iostream>
using namespace std;

class Base {
public:
Base() {
cout << "Base class constructor" << endl;
}

virtual ~Base() { // Virtual destructor


cout << "Base class destructor" << endl;
}
};

class Derived : public Base {


public:
Derived() {
cout << "Derived class constructor" << endl;
}

~Derived() {
cout << "Derived class destructor" << endl;
}
};

int main() {
Base* ptr = new Derived(); // Base pointer pointing to derived object
delete ptr; // Calls the destructor of Derived class followed by Base class
destructor
return 0;
}

Output:
Base class constructor
Derived class constructor
Derived class destructor
Base class destructor

Explanation:
• The destructor in the base class is declared as virtual, so when we delete the Derived
object using a Base pointer, both the base and derived destructors are called.

3. Compile-time and Run-time Polymorphism


• Compile-time Polymorphism (Static Polymorphism): Achieved through function
overloading and operator overloading. The function to be called is resolved at compile
time.
• Run-time Polymorphism (Dynamic Polymorphism): Achieved through virtual functions
and inheritance. The function to be called is resolved at runtime based on the actual object
type.

4. Virtual Functions
A virtual function is a member function in a base class that you expect to be overridden in derived
classes. When a function is declared as virtual, C++ ensures that the correct function is called for an
object, regardless of the type of the pointer or reference.

Example: Virtual Function


#include <iostream>
using namespace std;

class Base {
public:
virtual void display() { // Virtual function
cout << "Base class display function" << endl;
}
};

class Derived : public Base {


public:
void display() override { // Overriding the base class function
cout << "Derived class display function" << endl;
}
};

int main() {
Base* ptr;
Derived obj;
ptr = &obj;
ptr->display(); // Output: Derived class display function (Run-time
polymorphism)
return 0;
}

Explanation:
• The display() function in Base is virtual, and the correct display() function is
called based on the actual object type (Derived), even though the pointer is of type
Base*.

5. Dynamic Constructors
Dynamic constructors are constructors that allocate memory dynamically for the data members of
the class. This can be done inside the constructor using the new operator.

Example: Dynamic Constructor


#include <iostream>
using namespace std;

class MyClass {
int* ptr;
public:
MyClass(int size) {
ptr = new int[size]; // Dynamically allocating memory for the array
}

~MyClass() {
delete[] ptr; // Deallocating the memory
}

void display() {
cout << "Displaying data..." << endl;
}
};

int main() {
MyClass obj(10); // Dynamically allocating memory in the constructor
obj.display();
return 0;
}

6. Abstract Classes and Concrete Classes


• Abstract Class: A class that contains at least one pure virtual function. It cannot be
instantiated directly.
• Concrete Class: A class that can be instantiated and does not contain any pure virtual
functions.

Example: Abstract and Concrete Classes


#include <iostream>
using namespace std;

class Abstract {
public:
virtual void show() = 0; // Pure virtual function (abstract)
};

class Concrete : public Abstract {


public:
void show() override {
cout << "Concrete class implementation" << endl;
}
};

int main() {
// Abstract obj; // Error: Cannot instantiate abstract class
Concrete obj;
obj.show(); // Output: Concrete class implementation
return 0;
}

Explanation:
• Abstract is an abstract class because it has a pure virtual function show().
• Concrete is a concrete class because it provides an implementation for the show()
function.
7. Pure Virtual Functions
A pure virtual function is a function that has no definition in the base class and is required to be
overridden in derived classes. It is declared by assigning = 0 to the function prototype.

Example: Pure Virtual Function


#include <iostream>
using namespace std;

class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};

class Circle : public Shape {


public:
void draw() override {
cout << "Drawing Circle" << endl;
}
};

class Square : public Shape {


public:
void draw() override {
cout << "Drawing Square" << endl;
}
};

int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();

shape1->draw(); // Output: Drawing Circle


shape2->draw(); // Output: Drawing Square

delete shape1;
delete shape2;
return 0;
}

Explanation:
• The draw() function is a pure virtual function in the Shape class, making Shape an
abstract class.
• Derived classes Circle and Square provide implementations for the draw() function.

8. Early Binding and Late Binding


• Early Binding: The function call is resolved at compile time (static polymorphism).
• Late Binding: The function call is resolved at runtime, typically used with virtual functions
(dynamic polymorphism).
9. Memory Leak and Allocation Failures
A memory leak occurs when dynamically allocated memory is not properly deallocated using
delete or delete[], causing memory to be lost. Allocation failures happen when the system
cannot allocate memory using new (usually due to insufficient memory).

Example: Memory Leak


#include <iostream>
using namespace std;

int main() {
int* ptr = new int(10); // Dynamically allocating memory
// Forgot to deallocate memory, causing a memory leak
return 0;
}

Explanation:
• In this case, memory is allocated with new but never freed, causing a memory leak.

Example: Allocation Failure


#include <iostream>
using namespace std;

int main() {
try {
int* ptr = new int[1000000000000]; // Trying to allocate too much
memory
} catch (bad_alloc& e) {
cout << "Memory allocation failed: " << e.what() << endl;
}
return 0;
}

Explanation:
• If the system cannot allocate the required memory, a std::bad_alloc exception is
thrown.

Concept Description
Dynamic Memory
Memory is allocated and deallocated using new and delete .
Allocation
Virtual Destructors Ensures correct destructor calls in inheritance hierarchies.
Compile-time
Resolved at compile time (function overloading, operator overloading).
Polymorphism
Run-time Polymorphism Resolved at runtime using virtual functions and inheritance.
Functions with no implementation in base class, forcing derived classes
Pure Virtual Functions
to provide one.
Memory Leak Occurs when dynamically allocated memory is not freed.
UNIT 1

Exception Handling, Templates, and Standard Template


Library (STL) in C++

1. Basics of Exception Handling


Exception handling is a mechanism to handle runtime errors, allowing the program to deal with
unexpected situations without crashing. In C++, exceptions are handled using the try, throw, and
catch blocks.

• try block: Contains the code that might throw an exception.


• throw statement: Used to throw an exception when a problem occurs.
• catch block: Catches the thrown exception and handles it.

2. Exception Handling Mechanism


The exception handling mechanism in C++ helps in isolating the error-handling code from the
regular logic of the program. This is done by using the try and catch blocks. If an exception is
thrown, the corresponding catch block is executed.

Example: Basic Exception Handling


#include <iostream>
using namespace std;

int divide(int a, int b) {


if (b == 0) {
throw "Division by zero is not allowed!"; // Throwing an exception
}
return a / b;
}

int main() {
try {
int result = divide(10, 0); // This will throw an exception
cout << "Result: " << result << endl;
} catch (const char* msg) { // Catching the exception
cout << "Error: " << msg << endl; // Output: Error: Division by zero is
not allowed!
}
return 0;
}

Explanation:
• The divide function checks if b is zero and throws an exception using throw.
• The catch block catches the exception and displays an error message.
3. Throwing Mechanism
The throw keyword is used to throw an exception in C++. It is typically followed by an object that
represents the error. The exception can be of any type, such as built-in types, custom classes, or
pointers.

Example: Throwing an Exception


#include <iostream>
using namespace std;

void test() {
throw 10; // Throwing an integer exception
}

int main() {
try {
test(); // Function that throws an exception
} catch (int e) { // Catching integer exception
cout << "Caught exception: " << e << endl; // Output: Caught exception:
10
}
return 0;
}

Explanation:
• The throw 10; statement throws an integer exception, which is caught by the catch
block.

4. Catching Mechanism
The catch block is used to catch exceptions thrown by a try block. It follows the try block and
can catch exceptions of different types.

Example: Catching Different Types of Exceptions


#include <iostream>
using namespace std;

void test(int x) {
if (x == 0)
throw "Zero is not allowed"; // Throwing string exception
else
throw 5; // Throwing integer exception
}

int main() {
try {
test(0); // This will throw a string exception
} catch (const char* msg) {
cout << "Caught exception: " << msg << endl; // Output: Caught
exception: Zero is not allowed
}

try {
test(1); // This will throw an integer exception
} catch (int e) {
cout << "Caught exception: " << e << endl; // Output: Caught exception:
5
}

return 0;
}

Explanation:
• The catch block can catch exceptions of specific types (such as strings and integers).
• Different catch blocks can handle different exception types.

5. Rethrowing an Exception
Sometimes, you may want to catch an exception and then throw it again for further processing by
another handler or to log the error.

Example: Rethrowing an Exception


#include <iostream>
using namespace std;

void test() {
try {
throw 10; // Throwing an integer exception
} catch (int e) {
cout << "Caught exception: " << e << endl;
throw; // Rethrowing the same exception
}
}

int main() {
try {
test(); // Calls the function which will rethrow the exception
} catch (int e) {
cout << "Rethrown exception caught in main: " << e << endl; // Output:
Rethrown exception caught in main: 10
}
return 0;
}

Explanation:
• The exception is caught inside the test function and then rethrown using throw;.
• The main function catches the rethrown exception.

6. Function Templates and Class Templates


Templates in C++ allow you to define functions or classes that can operate with any data type.
• Function Template: A template for creating functions that can work with different types.
• Class Template: A template for creating classes that can work with any data type.

Example: Function Template


#include <iostream>
using namespace std;

template <typename T>


T add(T a, T b) {
return a + b;
}

int main() {
cout << add(5, 10) << endl; // Output: 15
cout << add(3.5, 2.5) << endl; // Output: 6.0
return 0;
}

Explanation:
• template <typename T> defines a function template that works with any data type T.
• The add function can be used for different types, such as integers or doubles.

Example: Class Template


#include <iostream>
using namespace std;

template <typename T>


class Box {
private:
T value;
public:
Box(T val) : value(val) {}
T getValue() { return value; }
};

int main() {
Box<int> intBox(10);
Box<double> doubleBox(3.14);

cout << intBox.getValue() << endl; // Output: 10


cout << doubleBox.getValue() << endl; // Output: 3.14
return 0;
}

Explanation:
• Box<T> is a class template, and it can be instantiated with different types, like int and
double.

7. Class Template with Inheritance


Class templates can also be used with inheritance. Derived classes can inherit from a template class.

Example: Class Template with Inheritance


#include <iostream>
using namespace std;

template <typename T>


class Base {
protected:
T value;
public:
Base(T val) : value(val) {}
virtual void display() { cout << "Base value: " << value << endl; }
};
template <typename T>
class Derived : public Base<T> {
public:
Derived(T val) : Base<T>(val) {}
void display() override { cout << "Derived value: " << this->value <<
endl; }
};

int main() {
Derived<int> obj(20);
obj.display(); // Output: Derived value: 20
return 0;
}

Explanation:
• The Derived class inherits from the Base class template, and it can access and display the
value member.

8. Introduction to STL (Standard Template Library)


The Standard Template Library (STL) in C++ provides a set of template classes and functions
that implement common data structures and algorithms. It includes:
• Containers: Objects that store data (e.g., vector, list, map).
• Algorithms: Functions to perform operations on data (e.g., sort, find).
• Iterators: Objects used to traverse containers.

9. STL Containers: Vector and List


• Vector: A dynamic array that can grow in size.
• List: A doubly linked list that allows fast insertions and deletions.

Example: STL Vector


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

int main() {
vector<int> vec = {1, 2, 3, 4, 5};

for (int val : vec) {


cout << val << " "; // Output: 1 2 3 4 5
}

vec.push_back(6); // Adding an element to the vector


cout << "\nAfter push_back: " << vec.back() << endl; // Output: 6
return 0;
}

Explanation:
• vector<int> is a container that stores integers.
• The push_back() function adds an element at the end of the vector.
Example: STL List
#include <iostream>
#include <list>
using namespace std;

int main() {
list<int> lst = {10, 20, 30};

lst.push_front(5); // Adds element to the front of the list


lst.push_back(40); // Adds element to the back of the list

for (int val : lst) {


cout << val << " "; // Output: 5 10 20 30 40

}
return 0;

**Explanation:**
- `list<int>` is a container that stores integers in a doubly linked list.
- `push_front()` and `push_back()` allow insertion at the beginning and end of
the list, respectively.

---

Topic Description
Exception
Mechanism to handle runtime errors using try , throw , and catch blocks.
Handling
Function
Allows the creation of functions that can operate with any data type.
Templates
Class Templates Allows the creation of classes that can operate with any data type.
Predefined classes like vector , list , and map that store data in different
STL Containers
ways.
Functions that perform operations like sorting, searching, and modifying data
STL Algorithms
in containers.
Objects used to iterate through containers,
STL Iterators like begin() and end() methods.

You might also like