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

OOPs Unit-4 and Unit-5 Notes

Uploaded by

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

OOPs Unit-4 and Unit-5 Notes

Uploaded by

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

Unit-4

1. Constant data member and member function


A. Constant Data Member
A constant data member is a member of a class that is declared using the const keyword. Once a constant data
member is initialized, its value cannot be changed. This ensures that the member retains its initial value
throughout the lifetime of the object. Constant data members must be initialized either directly at the time of
their declaration (for C++11 and later) or through a constructor.
Example:
#include <iostream>
using namespace std;

class Example {
public:
const int x; // Constant data member

// Constructor to initialize the constant data member


Example(int val) : x(val) {}

void show() const {


cout << "Value of x: " << x << endl;
}
};

int main() {
Example obj(5);
obj.show();
// obj.x = 10; // This will cause a compile-time error
return 0;
}
Explanation:
• x is a constant data member.
• It is initialized through the constructor Example(int val).
• Attempting to modify x (e.g., obj.x = 10;) will result in a compilation error.

B. Constant Member Function


A constant member function is a member function that does not modify any data members of the class. It is
declared by appending the const keyword after the function declaration. It ensures that the function cannot
alter any member variables of the class.
Example:
#include <iostream>
using namespace std;

class Example {
public:
int y;

Example(int val) : y(val) {}

void show() const {


// y++; // This will cause a compile-time error
cout << "Value of y: " << y << endl;
}
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
void increment() {
y++; // Allowed as this function is not const
}
};

int main() {
Example obj(5);
obj.show(); // Allowed as show() is a constant function
obj.increment();
obj.show(); // Outputs incremented value
return 0;
}
Explanation:
• show() is a constant member function because it is marked with const after the function definition.
• It cannot modify any data members, so attempting to increment y inside show() results in an error.
• increment() is a non-const member function and can modify the y value.
Summary
• Constant Data Member: Cannot be modified after initialization.
• Constant Member Function: Ensures that it cannot modify any data members of the class.

2. Static data member and member function


In C++, static data members and static member functions belong to the class itself rather than to any specific
object of the class. They provide a way to share data and behavior across all instances of a class.

A. Static Data Member:


A static data member is a variable that is shared among all objects of a class. It is declared using the static
keyword inside the class. There is only one copy of this variable, regardless of how many objects of the class
are created.
Example: A BankAccount class where we want to keep track of the total number of accounts opened in
a bank.
#include <iostream>
using namespace std;

class BankAccount {
public:
static int totalAccounts; // Static data member

BankAccount() {
totalAccounts++; // Increment whenever a new account is created
}
};

// Initialize the static member outside the class


int BankAccount::totalAccounts = 0;

int main() {
BankAccount acc1;
BankAccount acc2;
cout << "Total accounts: " << BankAccount::totalAccounts << endl; // Output: 2
return 0;
}
Here, totalAccounts is a static data member, and it keeps track of the total number of BankAccount objects
created. Since it is static, it is shared among all instances (acc1 and acc2).

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


B. Static Member Function:
A static member function is a function that can be called without creating an object of the class. It can only
access static data members or other static member functions. It is also declared using the static keyword.

Example: Extending the BankAccount class with a static function to get the total accounts:
class BankAccount {
public:
static int totalAccounts;

BankAccount() {
totalAccounts++;
}

static int getTotalAccounts() {


return totalAccounts;
}
};
In the above code, getTotalAccounts() is a static member function. It can be called using the class name like
this:
cout << "Total accounts: " << BankAccount::getTotalAccounts() << endl;
This method provides a way to access totalAccounts without needing an instance of BankAccount.

C. Real-life Analogy:
Think of a static data member like a common counter in a bank that records the number of accounts. Every
time a new account is opened (an object is created), the counter increases, but there’s only one counter for all.
A static member function is like a public display that shows the number of accounts without needing to access
individual accounts.

3. Polymorphism
Polymorphism in C++ is a fundamental concept in object-oriented programming (OOP) that allows a function
or an object to take on many forms. It enables a single interface to represent different underlying forms (data
types). Polymorphism is key to flexibility and extensibility in OOP and is broadly classified into compile-time
(static) and runtime (dynamic) polymorphism.

A. 1. Compile-time Polymorphism:
Compile-time polymorphism is achieved through function overloading and operator overloading. It is
resolved during the compilation of the program.

1) Function Overloading:
This allows multiple functions with the same name but different parameters. The compiler determines which
function to call based on the arguments used during the function call.
Example: Function Overloading

#include <iostream>
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
using namespace std;

class Printer {
public:
void print(int num) {
cout << "Printing an integer: " << num << endl;
}
void print(double num) {
cout << "Printing a double: " << num << endl;
}
void print(string str) {
cout << "Printing a string: " << str << endl;
}
};

int main() {
Printer p;
p.print(5); // Calls the version with an integer parameter
p.print(5.5); // Calls the version with a double parameter
p.print("Hello"); // Calls the version with a string parameter
return 0;
}
In this example, the print function is overloaded with different parameter types. Depending on the argument
type, the appropriate version of print is called.

2) Operator Overloading:
This allows existing C++ operators to be redefined to work with user-defined data types.
For example, the + operator can be overloaded to add two complex numbers.
Example: Operator Overloading
#include <iostream>
using namespace std;

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

// Overloading the '+' operator


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

int main() {
Complex c1(5, 3), c2(2, 4);
Complex c3 = c1 + c2; // Uses overloaded '+' operator
cout << "Result: " << c3.real << " + " << c3.imag << "i" << endl;
return 0;
}
In this example, the + operator is overloaded to add two Complex numbers, which results in compile-time
polymorphism.

B. Runtime Polymorphism:
Runtime polymorphism is achieved through inheritance and virtual functions, where a base class pointer or
reference is used to refer to derived class objects. It is resolved during program execution.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


1) Virtual Functions:
A virtual function is a function in a base class that is declared using the virtual keyword. When a derived class
overrides this function, and a base class pointer points to a derived class object, the overridden version is
called instead of the base class version.
Example: Virtual Functions

#include <iostream>
using namespace std;

class Animal {
public:
virtual void sound() {
cout << "Animal makes a sound" << endl;
}
};

class Dog : public Animal {


public:
void sound() override {
cout << "Dog barks" << endl;
}
};

class Cat : public Animal {


public:
void sound() override {
cout << "Cat meows" << endl;
}
};

int main() {
Animal* a;
Dog d;
Cat c;

a = &d;
a->sound(); // Outputs: Dog barks

a = &c;
a->sound(); // Outputs: Cat meows

return 0;
}
In this example, the sound() function is declared as virtual in the Animal base class. When a base class pointer
a points to Dog and Cat objects, the overridden sound() function of the derived class is called. This is
dynamic polymorphism.

C. Real-life Analogy:
Think of polymorphism like a remote control that can operate multiple devices. For instance, a TV remote can
control a TV, but if it has universal functions, it can also operate a sound system or a DVD player. The remote
remains the same (interface), but the way it functions (underlying behavior) changes based on the device it is
controlling. In C++, the base class (Animal) acts like the remote, and derived classes (Dog, Cat) are like
different devices. The sound() function behaves differently depending on the actual object being referenced.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


D. Key Points of Polymorphism:
Code Reusability: Allows a single interface to work with multiple types, reducing code duplication.
Extensibility: New derived classes can be added without changing the existing code.
Flexibility: Functions like sound() in the example can be generalized in the base class, with specific behaviors
defined in derived classes.
By using polymorphism, C++ allows for more versatile and maintainable code, making it easier to build
scalable and extensible applications.

4. Operator overloading
Operator overloading is an essential feature in C++ that allows operators to be redefined to perform
specific tasks for user-defined data types. It essentially enables operators to work with custom
classes and structures in a way similar to primitive types, enhancing code readability, flexibility, and
modularity. Operator overloading is an integral part of Object-Oriented Programming in C++, as it
allows operators to be used naturally with objects while adhering to principles of encapsulation and
abstraction.

A. What is Operator Overloading?


Operator overloading allows you to define or modify the behavior of operators (such as +, -, *, /,
etc.) for custom data types. By overloading operators, you can make complex operations on objects
straightforward and intuitive. For instance, if you have a class representing complex numbers, you
can overload the + operator to add two complex number objects directly with a + b, where a and b
are instances of the Complex class.

B. List of Operators that Can Be Overloaded


The majority of operators in C++ can be overloaded, including:

• Arithmetic Operators: +, -, *, /, %
• Relational Operators: ==, !=, <, >, <=, >=
• Logical Operators: &&, ||, !
• Bitwise Operators: &, |, ^, ~, <<, >>
• Assignment Operators: =, +=, -=, *=, /=, %= etc.
• Increment/Decrement Operators: ++, --

C. List of Operators that Cannot Be Overloaded


Some operators are not eligible for overloading in C++:

• Scope Resolution Operator: ::


• Sizeof Operator: sizeof
• Conditional (Ternary) Operator: ?:
• Member Access Operators: ., .*
• Type Casting Operators: const_cast, static_cast, dynamic_cast, reinterpret_cast

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


D. Syntax for Operator Overloading
To overload an operator in C++, you define a function with the keyword operator followed by the
operator symbol. Overloaded operators can be defined as either member functions or friend
functions.

// Syntax for a member function


ReturnType ClassName::operatorOp(ParameterList) {
// Function Body
}

// Syntax for a friend function


friend ReturnType operatorOp(ParameterList) {
// Function Body
}

E. Unary Operator Overloading by Member Function


Unary operators, such as ++, --, -, and !, can be overloaded to perform custom actions on objects.
When overloaded as a member function, unary operators do not take any arguments for prefix
versions but take an int parameter for postfix versions.

1) Prefix Increment (++) Overloading


The prefix increment operator increments the object’s value before using it.

#include <iostream>
using namespace std;

class Check
{
private:
int i;
public:
Check(): i(0) { }
void operator ++()
{ ++i; }
void Display()
{ cout << "i=" << i << endl; }
};

int main()
{
Check obj;

// Displays the value of data member i for object obj


obj.Display();

// Invokes operator function void operator ++( )


++obj;

// Displays the value of data member i for object obj


obj.Display();

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


return 0;
}
Output
i=0
i=1

2) Postfix Increment (++) Overloading


The postfix increment operator increments the object’s value after its usage and takes an integer
parameter as a placeholder to differentiate from the prefix version.

#include <iostream>
using namespace std;

class Check
{
private:
int i;
public:
Check(): i(0) { }
Check operator ++ ()
{
Check temp;
temp.i = ++i;
return temp;
}

// Notice int inside barcket which indicates postfix increment.


Check operator ++ (int)
{
Check temp;
temp.i = i++;
return temp;
}

void Display()
{ cout << "i = "<< i <<endl; }
};

int main()
{
Check obj, obj1;
obj.Display();
obj1.Display();

// Operator function is called, only then value of obj is assigned to obj1


obj1 = ++obj;
obj.Display();
obj1.Display();

// Assigns value of obj to obj1, only then operator function is called.


obj1 = obj++;
obj.Display();
obj1.Display();

return 0;
}
Output

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


i = 0
i = 0
i = 1
i = 1
i = 2
i = 1

F. Unary Operator Overloading by Friend Function


Unary operators can also be overloaded using friend functions, which allow non-member functions
to access private data.

1) Prefix Increment (++) Using Friend Function


In this case, we define the operator outside the class but declare it as a friend within the class.

#include <iostream>
using namespace std;

class Number {
private:
int value;

public:
// Constructor
Number(int v = 0) : value(v) {}

// Friend function for prefix increment


friend void operator++(Number &num);

// Display the value


void display() const {
cout << "Value: " << value << endl;
}
};

// Definition of friend function for prefix increment


void operator++(Number &num) {
++num.value;
}

int main() {
Number num(5);

cout << "Initial ";


num.display();

// Prefix increment
++num;

cout << "After prefix increment ";


num.display();
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
return 0;
}
Output
Initial Value: 5
After prefix increment Value: 6

2) Postfix Increment (++) Using Friend Function


The operator++ takes an additional dummy int parameter to distinguish it from the prefix version.

#include <iostream>
using namespace std;

class Number {
private:
int value;

public:
// Constructor
Number(int v = 0) : value(v) {}

// Friend function for postfix increment


friend Number operator++(Number &num, int);

// Display the value


void display() const {
cout << "Value: " << value << endl;
}
};

// Definition of friend function for postfix increment


Number operator++(Number &num, int) {
Number temp = num; // Save the current state
num.value++; // Increment the value
return temp; // Return the saved state
}

int main() {
Number num(5);

cout << "Initial ";


num.display();

// Postfix increment
Number temp = num++;

cout << "After postfix increment, original ";


num.display();

cout << "Value of temp (before increment) ";


temp.display();

return 0;
}

Output
Initial Value: 5
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
After postfix increment, original Value: 6
Value of temp (before increment) Value: 5

G. Binary Operator Overloading by Member Function


Binary operators take two operands, for instance, +, -, *, /, etc. When overloaded as member
functions, the left-hand operand is implicitly passed, and the right-hand operand is taken as a
parameter.

1) Example: Overloading + Operator for Addition


In this example, we overload + to add two objects of a class.

#include <iostream>
using namespace std;

class Number {
private:
int value;

public:
// Constructor
Number(int v = 0) : value(v) {}

// Overload + operator
Number operator+(const Number &obj) {
return Number(value + obj.value); // Add the values of two objects
}

// Display the value


void display() const {
cout << "Value: " << value << endl;
}
};

int main() {
Number num1(10), num2(20);

cout << "Number 1: ";


num1.display();

cout << "Number 2: ";


num2.display();

// Use overloaded + operator


Number sum = num1 + num2;

cout << "Sum: ";


sum.display();

return 0;
}
Output
Number 1: Value: 10
Number 2: Value: 20
Sum: Value: 30

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


2) Operator overloading for the + operator to concatenate two
strings
#include <iostream>
#include <string>
using namespace std;

class String {
private:
string value;

public:
// Constructor
String(const string &v = "") : value(v) {}

// Overload + operator for concatenation


String operator+(const String &obj) {
return String(value + obj.value); // Concatenate the strings
}

// Display the string


void display() const {
cout << "String: " << value << endl;
}
};

int main() {
String str1("Hello"), str2("World");

cout << "First String: ";


str1.display();

cout << "Second String: ";


str2.display();

// Use overloaded + operator


String result = str1 + " " + str2;

cout << "Concatenated String: ";


result.display();

return 0;
}
Output
First String: Hello
Second String: World
Concatenated String: Hello World

H. Binary Operator Overloading by Friend Function


Using friend functions, we can access private data members of the objects.

1) Example: Overloading + Operator using Friend Function


This example shows how to overload the + operator to add two objects.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


#include <iostream>
using namespace std;

class Number {
private:
int value;

public:
// Constructor
Number(int v = 0) : value(v) {}

// Friend function to overload +


friend Number operator+(const Number &num1, const Number &num2);

// Display the value


void display() const {
cout << "Value: " << value << endl;
}
};

// Definition of friend function


Number operator+(const Number &num1, const Number &num2) {
return Number(num1.value + num2.value); // Add the values
}

int main() {
Number num1(15), num2(25);

cout << "Number 1: ";


num1.display();

cout << "Number 2: ";


num2.display();

// Use overloaded + operator


Number result = num1 + num2;

cout << "Sum: ";


result.display();

return 0;
}
Output
Number 1: Value: 15
Number 2: Value: 25
Sum: Value: 40

I. Summary of Calling Rules


1. Unary Operators:
o Member Functions: Unary operators don’t require parameters for prefix, but take an int
parameter for postfix.
o Friend Functions: Unary friend functions take the object as a parameter (by reference) and
require an additional int parameter for postfix.
2. Binary Operators:

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


o Member Functions: The left operand is implicitly passed (as the calling object), and the
right operand is taken as a parameter.
o Friend Functions: Both operands are explicitly passed as parameters to the function.

5. Dynamic binding and virtual function


Dynamic binding and virtual functions are fundamental concepts in C++ that support polymorphism,
allowing the program to choose the appropriate function at runtime rather than compile time. These
mechanisms are particularly useful in object-oriented programming (OOP) when working with
inheritance and polymorphism.

A. What is Dynamic Binding?


Dynamic binding, also known as late binding, is a process where the code to be executed is
determined at runtime instead of compile time. In C++, this happens when a function is marked as
"virtual" in the base class. When a derived class overrides this virtual function, C++ determines
which function to call based on the actual object type at runtime, not the pointer type.

Dynamic binding is essential when you want to work with derived classes through base class
pointers or references, and you want the program to automatically select the overridden function in
the derived class.

B. What is a Virtual Function?


A virtual function is a member function in the base class that you expect to override in derived
classes. Declaring a function as virtual ensures that when you refer to an object of a derived class
through a base class pointer or reference, the overridden function in the derived class will be called
instead of the function in the base class.

1) Syntax for Declaring a Virtual Function


The virtual keyword is used in the base class function declaration. Here’s a basic syntax for
declaring a virtual function:

class Base {
public:
virtual void show() {
cout << "Base class show function called" << endl;
}
};

In this example, show is a virtual function in the Base class, and derived classes can override it.
When called through a pointer or reference of the base type, the derived class version will be
invoked, thanks to dynamic binding.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


C. Example of Virtual Functions and Dynamic Binding

#include <iostream>
using namespace std;

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

// Non-virtual function
void show() {
cout << "Show from Base class" << endl;
}

virtual ~Base() {} // Virtual destructor (best practice for base classes)


};

class Derived : public Base {


public:
// Overriding virtual function
void display() override {
cout << "Display from Derived class" << endl;
}

// Non-virtual function
void show() {
cout << "Show from Derived class" << endl;
}
};

int main() {
Base *basePtr; // Base class pointer
Derived derivedObj; // Derived class object

basePtr = &derivedObj;

cout << "Using virtual function:" << endl;


basePtr->display(); // Calls Derived class's display() due to dynamic binding

cout << "Using non-virtual function:" << endl;


basePtr->show(); // Calls Base class's show() due to static binding

return 0;
}
Output
Using virtual function:
Display from Derived class
Using non-virtual function:
Show from Base class

2) Explanation of the Example



Here, Animal is the base class with a virtual function sound.

Dog and Cat are derived classes that override the sound function.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
• animalPtr is a pointer of type Animal*, and it is used to point to objects of derived classes Dog and
Cat.
• Due to dynamic binding, calling animalPtr->sound() invokes the sound function of the actual
object type, which could be either Dog or Cat.

D. Benefits of Virtual Functions and Dynamic Binding


1. Polymorphism: Enables runtime polymorphism, allowing objects of different derived classes to be
treated through a base class pointer/reference.
2. Flexibility and Extensibility: Makes it easy to add new derived classes without modifying existing
code.
3. Code Reusability: Allows for reusable code, as functions in the base class can work with any derived
class that overrides them.

E. Virtual Table (vtable) and Virtual Pointer (vptr)


C++ implements dynamic binding using a mechanism called the virtual table (vtable) and virtual
pointer (vptr). Each class with virtual functions has a vtable that stores pointers to the virtual
functions for that class. Each object of a class with virtual functions has a vptr pointing to the vtable
of its class.

When a virtual function is called through a base class pointer, C++ looks up the function in the
vtable of the actual object and calls the appropriate function.

1. vtable: An array of function pointers where each entry points to a virtual function that can be called
by the class.
2. vptr: A hidden pointer in each object that points to the vtable of the object’s class.

F. Pure Virtual Functions and Abstract Classes


A pure virtual function is a virtual function with no implementation in the base class. It is declared
by assigning 0 to the function. Pure virtual functions make a class abstract, meaning you cannot
create objects of that class; it can only serve as a base class.

class Animal {
public:
virtual void sound() = 0; // Pure virtual function
};

G. Example of Pure Virtual Functions and Abstract Classes


#include <iostream>
using namespace std;

// Abstract class
class Shape {
public:
// Pure virtual function
virtual void area() const = 0;

// Virtual destructor (best practice for base classes)


virtual ~Shape() {}

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


};

// Derived class: Rectangle


class Rectangle : public Shape {
private:
double length, width;

public:
Rectangle(double l, double w) : length(l), width(w) {}

// Overriding the pure virtual function


void area() const override {
cout << "Area of Rectangle: " << (length * width) << endl;
}
};

// Derived class: Circle


class Circle : public Shape {
private:
double radius;

public:
Circle(double r) : radius(r) {}

// Overriding the pure virtual function


void area() const override {
cout << "Area of Circle: " << (3.14159 * radius * radius) << endl;
}
};

int main() {
Shape* shapePtr; // Pointer to the abstract class

// Rectangle
Rectangle rect(10.5, 5.5);
shapePtr = &rect;
cout << "Rectangle details:" << endl;
shapePtr->area();

// Circle
Circle circ(7.0);
shapePtr = &circ;
cout << "\nCircle details:" << endl;
shapePtr->area();

return 0;
}
Output
Rectangle details:
Area of Rectangle: 57.75
Circle details:
Area of Circle: 153.938

In this example:

• Shape is an abstract class because it has a pure virtual function draw.


• Circle and Square are derived classes that provide implementations for the draw function.
• You can only create pointers or references of type Shape, not objects directly.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


H. Rules and Considerations for Using Virtual Functions
1. Virtual functions should be accessed through a pointer or reference to achieve polymorphism.
2. Destructor of the Base Class: If a base class has virtual functions, its destructor should also be
virtual to ensure that the derived class destructor is called when deleting an object through a base
class pointer.
3. Overriding with the Same Signature: The derived class function must have the same name and
parameters as the base class virtual function to override it correctly.

I. Virtual Destructors
When you delete a derived class object through a base class pointer, C++ requires a virtual
destructor to ensure that the derived class’s destructor is called. If the base class destructor is not
virtual, only the base class’s destructor will be called, leading to resource leaks.

#include <iostream>
using namespace std;

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

virtual ~Base() {
cout << "Base destructor called." << endl;
}
};

class Derived : public Base {


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

~Derived() override {
cout << "Derived destructor called." << endl;
}
};

int main() {
// Base class pointer pointing to a Derived class object
Base* basePtr = new Derived();

// Deleting the object


delete basePtr;

return 0;
}
Output-
Base constructor called.
Derived constructor called.
Derived destructor called.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


Base destructor called.
Explanation
1. Base Class with Virtual Destructor:
o The Base class has a virtual destructor: virtual ~Base().
o This ensures that the destructor of the derived class (Derived) is called first when an object is
deleted through a base class pointer.
2. Derived Class:
o The Derived class overrides the destructor of the base class.
o When the object is destroyed, both the Derived destructor and the Base destructor are
executed in the proper order.
3. Dynamic Allocation and Deletion:
o A Base* pointer points to a dynamically allocated Derived object.
o When delete basePtr is called, the Derived destructor is executed first (due to the virtual
destructor), followed by the Base destructor.
4. Without Virtual Destructor:
o If the base class destructor is not virtual, only the Base destructor will be called, leading to
potential resource leaks or undefined behavior.

J. Advantages of Dynamic Binding and Virtual Functions


• Achieving Polymorphism: Dynamic binding is the foundation of polymorphism, allowing different
objects to respond to the same function call in their unique ways.
• Improved Code Maintainability: Changes can be made to derived classes without affecting the base
class code.
• Reduces Code Duplication: Base class functions can handle operations generically, reducing the
need for redundant code.

K. Limitations and Considerations


• Performance Overhead: Virtual functions introduce a slight runtime overhead due to the vtable
lookup, though this is minimal in most applications.
• Memory Usage: The vtable and vptr add extra memory overhead, which can be significant in
systems with a large number of classes and virtual functions.
• Complexity: Improper use of virtual functions or not declaring destructors as virtual can lead to
resource leaks and undefined behavior.

In conclusion, dynamic binding and virtual functions enable C++ to implement polymorphism
effectively, supporting flexibility and modularity in code. They make it possible for a single function
call to operate on objects of various derived types, making programs easier to extend and maintain
while also improving code reusability.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


Unit-5
1. Exception handling
Exception handling in C++ is a mechanism for handling runtime errors in a program. It separates error-
handling code from regular code, making programs more robust and easier to maintain.

A. Exception:
An exception is an event that occurs during the execution of a program and disrupts the normal flow of
instructions. For example, division by zero, invalid memory access, or file not found.

B. Exception Handling Mechanism:


In C++, we handle exceptions with the help of the try and catch blocks, along with the throw keyword.
• try - code that may raise an exception
• throw - throws an exception when an error is detected
• catch - code that handles the exception thrown by the throw keyword
Note: The throw statement is not compulsory, especially if we use standard C++ exceptions.

C. Steps in Exception Handling


1. Throwing an Exception:
o Use the throw keyword to signal that an error or unexpected situation has occurred.
o You can throw any object, but exceptions are usually instances of the standard library class
std::exception or custom classes.
2. Catching an Exception:
o Use catch blocks to handle exceptions.
o Each catch block handles a specific type of exception.
3. Propagating Exceptions:
o If no matching catch block is found, the program terminates by calling std::terminate.

D. Features of Exception Handling


1. Multiple catch Blocks:
o A try block can be followed by multiple catch blocks to handle different types of exceptions.
2. Generic catch Block:
o A catch(...) block can catch all exceptions, regardless of type.
catch (...) {
cout << "A general exception occurred." << endl;
}
3. Re-throwing Exceptions:
o Use the throw statement without arguments in a catch block to re-throw the exception to
another handler.
4. Standard Exception Classes:

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


o C++ provides a set of standard exception classes, such as std::exception, std::runtime_error,
std::logic_error, etc.

E. Syntax for Exception Handling in C++


The basic syntax for exception handling in C++ is given below:
try {

// code that may raise an exception


throw argument;
}

catch (exception) {
// code to handle exception
}
Here, we have placed the code that might generate an exception inside the try block. Every try block is
followed by the catch block.
When an exception occurs, the throw statement throws an exception, which is caught by the catch block.
The catch block cannot be used without the try block.

Example 1: C++ Exception Handling


// program to divide two numbers
// throws an exception when the divisor is 0

#include <iostream>
using namespace std;

int main() {

double numerator, denominator, divide;

cout << "Enter numerator: ";


cin >> numerator;

cout << "Enter denominator: ";


cin >> denominator;

try {

// throw an exception if denominator is 0


if (denominator == 0)
throw 0;

// not executed if denominator is 0


divide = numerator / denominator;
cout << numerator << " / " << denominator << " = " << divide << endl;
}

catch (int num_exception) {


cout << "Error: Cannot divide by " << num_exception << endl;
}

return 0;
}
Output 1
Enter numerator: 72
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
Enter denominator: 0
Error: Cannot divide by 0
Output 2
Enter numerator: 72
Enter denominator: 3
72 / 3 = 24
Explanation
The above program divides two numbers and displays the result. But an exception occurs if the denominator
is 0.
To handle the exception, we have put the code divide = numerator / denominator; inside the try block. Now,
when an exception occurs, the rest of the code inside the try block is skipped.
The catch block catches the thrown exception and executes the statements inside it.
If none of the statements in the try block generates an exception, the catch block is skipped.

Working of try, throw, and catch statements in C++


Notice that we have thrown the int literal 0 with the code throw 0;.
We can throw any literal or variable or class, depending on the situation and depending on what we want to
execute inside the catch block.
The catch parameter int num_exception takes the value passed by the throw statement i.e. the literal 0.

F. Catching All Types of Exceptions


In exception handling, it is important that we know the types of exceptions that can occur due to the code in
our try statement.
This is so that we can use the appropriate catch parameters. Otherwise, the try...catch statements might not
work properly.
If we do not know the types of exceptions that can occur in our try block, then we can use the ellipsis
symbol ... as our catch parameter.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
try {
// code
}
catch (...) {
// code
}
Example
#include <iostream>
using namespace std;

int main() {
try {
throw "Unknown exception";
}
catch (const char* msg) {
cout << "Caught string exception: " << msg << endl;
}
catch (...) {
cout << "Caught an unknown exception" << endl;
}
return 0;
}
Output
Caught string exception: Unknown exception
• C++ Multiple catch Statements
In C++, we can use multiple catch statements for different kinds of exceptions that can result from a single
block of code.
try {
// code
}
catch (exception1) {
// code
}
catch (exception2) {
// code
}
catch (...) {
// code
}
Here, our program catches exception1 if that exception occurs. If not, it will catch exception2 if it occurs.
If there is an error that is neither exception1 nor exception2, then the code inside of catch (...) {} is executed.
Notes:
• catch (...) {} should always be the final block in our try...catch statement. This is because this block
catches all possible exceptions and acts as the default catch block.
• It is not compulsory to include the default catch block in our code.

Example: C++ Multiple catch Statements


This program divides two numbers and stores the result in an array element. There are two possible
exceptions that can occur in this program:
• If the array is out of bounds i.e. if the index of the array is greater than the size of the array
• If a number is divided by 0
These exceptions are caught in multiple catch statements.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
#include <iostream>
using namespace std;

int main() {

double numerator, denominator, arr[4] = {0.0, 0.0, 0.0, 0.0};


int index;

cout << "Enter array index: ";


cin >> index;

try {

// throw exception if array out of bounds


if (index >= 4)
throw "Error: Array out of bounds!";

// not executed if array is out of bounds


cout << "Enter numerator: ";
cin >> numerator;

cout << "Enter denominator: ";


cin >> denominator;

// throw exception if denominator is 0


if (denominator == 0)
throw 0;

// not executed if denominator is 0


arr[index] = numerator / denominator;
cout << arr[index] << endl;
}

// catch "Array out of bounds" exception


catch (const char* msg) {
cout << msg << endl;
}

// catch "Divide by 0" exception


catch (int num) {
cout << "Error: Cannot divide by " << num << endl;
}

// catch any other exception


catch (...) {
cout << "Unexpected exception!" << endl;
}

return 0;
}
Output 1
Enter array index: 5
Error: Array out of bounds!
Explanation
Here, the array arr only has 4 elements. So, index cannot be greater than 3.
In this case, index is 5. So we throw a string literal "Error: Array out of bounds!". This exception is caught by
the first catch block.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


Notice the catch parameter const char* msg. This indicates that the catch statement takes a string literal as an
argument.
Output 2
Enter array index: 2
Enter numerator: 5
Enter denominator: 0
Error: Cannot divide by 0
Explanation
Here, the denominator is 0. So we throw the int literal 0. This exception is caught by the second catch block.
If any other exception occurs, it is caught by the default catch block.
Output 3
Enter array index: 2
Enter numerator: 5
Enter denominator: 2
2.5
Explanation
Here, the program runs without any problem as no exception occurs.

G. C++ Standard Exception


C++ has provided us with a number of standard exceptions that we can use in our exception handling. Some
of them are shown in the table below.
Exception Description
std::bad_alloc Thrown when a dynamic memory allocation fails.
std::bad_cast Thrown by C++ when an attempt is made to perform a dynamic_cast to an invalid type.
std::bad_exception Typically thrown when an exception is thrown and it cannot be rethrown.
std::exception It is an exception and parent class of all standard C++ exceptions.
std::logic_failure It is an exception that can be detected by reading a code.
std::runtime_error It is an exception that cannot be detected by reading a code.
std::bad_exception It is used to handle the unexpected exceptions in a c++ program. Typically thrown when
an exception is thrown and it cannot be rethrown.
std::bad_typeid This exception is generally be thrown by typeid.
std::bad_alloc This exception is generally be thrown by new.

Example: User-Defined Exception


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

class MyException : public exception {


Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
public:
const char* what() const noexcept override {
return "Custom exception occurred!";
}
};

int main() {
try {
throw MyException();
}
catch (const MyException& e) {
cout << e.what() << endl;
}
return 0;
}
Output
Custom exception occurred!

H. Rethrowing Exceptions in C++


Rethrowing an exception in C++ refers to the act of throwing an exception that has been caught by a catch
block, which allows it to propagate further up the call stack. This is useful when you want to handle the
exception partially (e.g., logging the error) and then pass it along to another handler (such as a higher-level
function) for further handling or to allow the program to terminate cleanly.
Rethrowing can be done using the throw keyword without specifying an exception object, which rethrows the
current exception being handled.

1) Syntax of Rethrowing
catch (exception_type &e) {
// Handle the exception partially (logging, cleanup, etc.)

// Rethrow the caught exception


throw;
}
When you use throw; in a catch block, it rethrows the currently caught exception and allows it to propagate to
another catch block, higher in the call stack, or if no other catch block is found, the program terminates.
Example of Rethrowing Exceptions
#include <iostream>
#include <stdexcept>
using namespace std;

void function1() {
try {
// Simulate an error
throw runtime_error("Error occurred in function1");
} catch (const runtime_error& e) {
cout << "Caught in function1: " << e.what() << endl;

// Rethrow the exception to propagate it further


throw;
}
}

void function2() {
try {
function1();
} catch (const runtime_error& e) {
cout << "Caught in function2: " << e.what() << endl;
}

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


}

int main() {
try {
function2();
} catch (const runtime_error& e) {
cout << "Caught in main: " << e.what() << endl;
}

return 0;
}
Output
Caught in function1: Error occurred in function1
Caught in function2: Error occurred in function1
Caught in main: Error occurred in function1
Explanation of the Example
1. function1:
o In function1(), we simulate an error by throwing a runtime_error with a message "Error
occurred in function1".
o The exception is caught in the catch block of function1, where we log the message "Caught in
function1".
o After handling the error partially, we use throw; to rethrow the exception to the next level.
2. function2:
o function2() calls function1() inside a try block.
o When function1() rethrows the exception, it is caught again in the catch block of function2.
o The message "Caught in function2" is printed.
3. main:
o The main() function calls function2().
o When the exception is rethrown from function2(), it is finally caught in the main() function's
catch block.
o The message "Caught in main" is printed.

2) Key Points of Rethrowing


1. Partial Handling: Sometimes, you may want to partially handle an exception (e.g., logging or
cleanup), but let the exception propagate further to be handled at a higher level. This is where
rethrowing comes in.
2. Preserving the Exception: Rethrowing the exception ensures that the original exception object (with
all its data) is preserved and passed along.
3. Control Flow: After an exception is rethrown, the program will continue to search for a matching
catch block in the next levels of the call stack.

3) Limitations of Rethrowing
1. No Exception Type Change: The exception that is rethrown must be of the same type as the one that
was caught. You cannot change the type of an exception after it has been caught.
2. Handling Multiple Exceptions: If multiple exceptions are thrown and caught, it can sometimes
become complex to rethrow and handle each one in a structured way.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
I. Limitations of Exception Handling
1. Performance Overhead:
o Exception handling can introduce a slight performance cost due to runtime checks and stack
unwinding.
2. Hard to Debug:
o Excessive use of exceptions can make the code hard to follow and debug.
3. Not Suitable for All Errors:
o Exceptions are meant for exceptional cases, not regular control flow.
4. Compiler Dependency:
o Exception handling behavior may vary slightly across compilers.

2. Template
Templates in C++ allow writing generic functions and classes, meaning that the same code can work with
different data types. The C++ template mechanism is a powerful tool for writing reusable code, enabling the
creation of functions and classes that can operate with any data type without having to rewrite the code for
each type.

A. Types of Templates
1. Function Template: A function template allows the definition of a generic function that can operate
on different data types. The function is created once and can handle multiple types, determined at
compile-time.
2. Class Template: A class template allows the creation of a generic class that can work with different
data types. Like function templates, class templates are compiled for specific types when used.

B. Syntax of Templates
1) Function Template Syntax
template <typename T>
T add(T a, T b) {
return a + b;
}
• template <typename T> is the declaration of the template, where T is a placeholder for the type.
• The function add is created to add two values of type T.

2) Class Template Syntax


template <typename T>
class Box {
private:
T value;
public:
Box(T val) : value(val) {}
T getValue() {
return value;
}

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


};
• The class Box can hold any data type, defined when an object is instantiated.

C. Examples of Function Template and Class Template


1) Function Template Example
#include <iostream>
using namespace std;

// Function template for adding two values


template <typename T>
T add(T a, T b) {
return a + b;
}

int main() {
int intResult = add(10, 20); // Using template with int
double doubleResult = add(10.5, 20.5); // Using template with double

cout << "Sum of integers: " << intResult << endl;


cout << "Sum of doubles: " << doubleResult << endl;

return 0;
}
Output:
Sum of integers: 30
Sum of doubles: 31
In this example, the function template add() is used to add two integers and two doubles. The compiler
generates the appropriate code for each type.

2) Class Template Example


#include <iostream>
using namespace std;

// Class template for a Box that holds a value of type T


template <typename T>
class Box {
private:
T value;
public:
Box(T val) : value(val) {}
T getValue() {
return value;
}
};

int main() {
Box<int> intBox(10); // Creating a Box of integers
Box<double> doubleBox(3.14); // Creating a Box of doubles

cout << "Box containing integer: " << intBox.getValue() << endl;
cout << "Box containing double: " << doubleBox.getValue() << endl;

return 0;
}
Output:
Box containing integer: 10
Box containing double: 3.14

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


In this example, we define a Box class that can hold any type of value. By using Box<int> and Box<double>,
we create instances of the class to hold integers and doubles, respectively.

D. Valuable Applications of Templates


Templates are useful in many areas where generality and reusability are needed. Here are some common and
valuable applications of templates in C++:
1. Standard Template Library (STL): The Standard Template Library is a collection of template
classes and functions that provide general-purpose data structures and algorithms. For example,
containers like std::vector, std::list, and std::map are template classes, allowing them to work with any
data type.
2. Generic Algorithms: You can write algorithms that work with any type of container or data
structure. For instance, sorting or searching functions can be written in a generic way using templates.

E. Example: A Generic Sorting Algorithm


#include <iostream>
using namespace std;

// Template for a generic swap function


template <typename T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}

// Template for a generic sorting function


template <typename T>
void sortArray(T arr[], int size) {
for (int i = 0; i < size-1; i++) {
for (int j = i+1; j < size; j++) {
if (arr[i] > arr[j]) {
swap(arr[i], arr[j]);
}
}
}
}

int main() {
int intArr[] = {10, 2, 7, 5};
double doubleArr[] = {3.14, 1.59, 2.65, 4.22};

int intSize = sizeof(intArr)/sizeof(intArr[0]);


int doubleSize = sizeof(doubleArr)/sizeof(doubleArr[0]);

sortArray(intArr, intSize);
sortArray(doubleArr, doubleSize);

cout << "Sorted integer array: ";


for (int i = 0; i < intSize; i++) {
cout << intArr[i] << " ";
}
cout << endl;

cout << "Sorted double array: ";


for (int i = 0; i < doubleSize; i++) {
cout << doubleArr[i] << " ";
}
cout << endl;

return 0;
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
}
Output:
Sorted integer array: 2 5 7 10
Sorted double array: 1.59 2.65 3.14 4.22
This example shows how a generic sorting algorithm can be written using templates. The sortArray function
works with any data type (like int or double) by utilizing the template mechanism.

F. Pros of Using Templates


1. Code Reusability:
o Templates allow writing a single piece of code that can work for multiple types, reducing
code duplication.
2. Type Safety:
o Templates are checked at compile-time, providing type safety. The compiler ensures that
operations on types are valid, preventing runtime errors.
3. Generic Data Structures and Algorithms:
o Templates allow you to create data structures (like linked lists, stacks, queues) and algorithms
(like sorting, searching) that work for any type.
4. Efficiency:
o Template code is resolved at compile time, and thus there is no runtime overhead (other than
the code being generated for each type).

G. Cons of Using Templates


1. Code Bloat:
o Templates can lead to code bloat because a separate instance of the template is generated for
each type it is instantiated with. This increases the size of the compiled code.
2. Compilation Overhead:
o Template code is generated during compilation for each type, which can increase compilation
times. For large codebases, this can lead to performance issues during development.
3. Error Messages:
o Template-related error messages can be hard to decipher, especially when dealing with
complex template instantiations. Compiler errors involving templates can be cryptic and
difficult to understand.
4. Limited Debugging:
o Debugging template code can be challenging because the code is often generated
automatically by the compiler, making it harder to track down issues.

3. Stream class

In C++, a stream refers to a sequence of characters that are transferred between the program and input/output
(I/O) devices. Stream classes in C++ facilitate input and output operations on files and other I/O devices.
These classes have specific features to handle program input and output, making it easier to write portable
code that can be used across multiple platforms.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
To use streams in C++, you need to include the appropriate header file. For instance, to use input/output
streams, you would include the iostream header file. This library provides the necessary functions and classes
to work with streams, enabling you to read and write data to and from files and other I/O devices.
In this blog, we’ll be exploring four essential C++ stream classes:
• istream
• ostream
• ifstream
• ofstream
Object-oriented programming, such as C++, relies heavily on the concept of inheritance. Inheritance allows a
class to inherit properties from another class that has already been defined. Descendant classes can then add
their own unique properties, making them specializations of their parent class.
Take the stream class hierarchy as an example. In the diagram below (only a portion is shown), we can see
that ifstream is a specialization of istream. This means that an ifstream object is an istream object and inherits
all the properties of the istream class. Additionally, it adds some additional properties of its own.

The C++
stream class hierarchy consists of a number of classes that define and provide different flows for objects in the
class. The hierarchy is structured in a way that starts with the top class, which is the ios class, followed by
other classes such as the istream, ostream, iostream, istream_withassign, and ostream_withassign classes.
The ios class is the parent class in the hierarchy and both the istream and ostream classes inherit from it.
These two classes together form the ios class, which is the highest level of the entire C++ stream class
hierarchy.
Other classes in the hierarchy provide functions for various operations, including assignment operations, such
as the _withassign classes.

A. 1. The istream class


This class is a general-purpose input stream and is used to read input from various sources, including the
console and files. One example of an istream is cin, which is a commonly used input stream for reading input
from the console. The istream class provides a range of functions for handling characters, strings, and objects,
including get, getline, read, ignore, putback, and cin.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


These functions enable developers to manipulate input in various ways. For example, the get function allows
developers to read a single character from the input stream, while the getline function reads an entire line of
text and stores it in a string object. The read function is used to read a specific number of characters from the
input stream and store them in a buffer. Overall, the istream class is an essential component of input stream
handling in C++.
#include <iostream>
using namespace std;
int main()
{
char a;
cin.get(a);
cout << a;
return 0;
}
The C++ istream class provides a set of functions and operators for reading data from various input sources.
Before using the istream class, we need to include the <iostream> header in our program.
Example 1: Reading Data From the Console
To read data from the console using istream, you can use the cin object with the extraction operator >>. Here's
an example:
#include <iostream>
using namespace std;

int main() {

int entered_number;

cout << "Enter an integer: ";

// read data from the console


cin >> entered_number;

cout << "You entered: " << entered_number << endl;

return 0;
}
Output
Enter an integer: 3
You entered: 3
In this example, cin represents the standard input stream that reads data from the keyboard. We use
the >> operator to extract the user's input and store it in the number variable.

1) The get() Function


The get() function of the istream class is primarily used for reading individual characters from the input
stream.
Key Characteristics
• Reading Characters: It reads the next character from the input stream and advances the stream's
internal position indicator.
• Single Character: Unlike the >> operator, get() reads characters as they are, including spaces, tabs,
and newline characters.
• Character Extraction: You can use it to extract characters into variables of type char or to store
them in character arrays (C-strings).

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


• Delimiter Control: It allows you to specify a delimiter character as an optional parameter. When you
specify a delimiter, get() stops reading characters when it encounters that delimiter. This is useful for
reading words or lines.

Example: C++ get() Function


#include <iostream>
using namespace std;

int main() {

char ch;

cout << "Enter a sentence: ";

// read the character one by one


// until a new line is encountered
while (cin.get(ch) && ch != '\n') {
cout << ch;
}

return 0;
}
Output
Enter a sentence: Hello World
Hello World
Here, we have used cin.get() to read a single character from the user.
Notice this part of the code:
while (cin.get(ch) && ch != '\n') {
cout << ch;
}
The loop reads characters one by one from standard input until a newline character is encountered. In each
iteration, it prints the character immediately as it is read.

2) C++ getline() Function


The getline() function in istream is used to read a line of text from the specified input stream (such as cin for
standard input).
Key Characteristics
• Reading Lines: Unlike theget() function, getline() reads entire lines of text, up to a specified
delimiter or the end of the line.
• Delimiter Control: You can specify a delimiter character like one that indicates the end of a line.
This allows you to read multiple lines of text sequentially.
• Buffer Size: It accepts an optional parameter to specify the maximum number of characters to read,
preventing buffer overflows and handling long lines gracefully.

Example: C++ getline() Function


#include <iostream>
using namespace std;

int main() {

string line;

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


cout << "Enter a line of text: ";

// read a line of input from user


getline(cin, line);

cout << "You entered: " << line << endl;

return 0;
}
Output
Enter a line of text: Hello
You entered: Hello

3) C++ ignore() Function


The ignore() function is used to skip a given length of characters in the input stream.
#include <iostream>
using namespace std;

int main() {

cout << "Enter a line of text: ";

char ch;

// ignore the next 5 characters from standard input


cin.ignore(5);

// read the sixth character and print the value


if (cin.get(ch)) {
cout << "Next character after ignoring 5 characters: " << ch << endl;
}

return 0;
}
Output
Enter a line of text: 12345678
Next character after ignoring 5 characters: 6
Here, cin.ignore(5); is instructing the input stream to ignore the next five characters that are entered by the
user.
After this, the if condition cin.get(ch) attempts to read the next character from the input stream after the
previous five have been ignored. If successful, it stores them in the ch variable.

4) cin.getline() Method in C++


The cin.getline() method in C++ is used to read a line of text from the input stream (cin) into a character array
or string variable. It is particularly useful when reading strings that may contain spaces, as the cin method
alone does not work well with spaces (it stops reading at the first space encountered).
Syntax of cin.getline()
cin.getline(charArray, size);
• charArray: A character array (or pointer to a character array) where the input will be stored.
• size: The maximum number of characters to be read, including the null terminator (\0).

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


Key Points of cin.getline()
1. Reading a Line: Unlike cin >> variable, which stops reading at the first whitespace character (space,
tab, newline), cin.getline() reads the entire line, including spaces, until it encounters a newline
character (\n).
2. Size Limitation: The method requires you to specify the size of the buffer (the character array) that
will hold the input. It will stop reading either when it reaches the specified size minus one (to leave
room for the null terminator) or when it encounters a newline character.
3. Input Overflow Handling: If the number of characters read exceeds the buffer size minus one, the
cin.getline() method discards the extra characters and sets the failbit of the input stream. You can
check this using cin.fail().
4. Null Terminator (\0): cin.getline() automatically adds a null terminator (\0) at the end of the string,
marking the end of the string.
Example of cin.getline()
#include <iostream>
using namespace std;

int main() {
char name[50];

cout << "Enter your full name: ";


cin.getline(name, 50); // Reading a line of up to 49 characters + null terminator

cout << "Your name is: " << name << endl;

return 0;
}
Output:
Enter your full name: John Doe
Your name is: John Doe
In this example, cin.getline() reads the entire line of input (including spaces), storing it in the name character
array. The size 50 ensures that the input is safely stored without overflowing the buffer.
Example with Input Overflow Handling
If the input exceeds the specified size, cin.getline() will discard the extra characters and set the failbit.
#include <iostream>
using namespace std;

int main() {
char name[10];

cout << "Enter your name: ";


cin.getline(name, 10); // Only reads up to 9 characters

if (cin.fail()) {
cout << "Input is too long!" << endl;
} else {
cout << "Your name is: " << name << endl;
}

return 0;
}
Output (if input exceeds the size):
Enter your name: Johnathan
Input is too long!

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


Here, the buffer size is 10, so if the user enters more than 9 characters, cin.getline() will stop reading after 9
characters and set the failbit. You can check for this condition using cin.fail().

Key Differences Between cin.getline() and cin >>


1. Handling Spaces:
o cin >> stops reading at the first whitespace, so it cannot handle multi-word strings.
o cin.getline() reads the entire line, including spaces.
2. Buffer Size:
o cin >> does not require a buffer size to be specified.
o cin.getline() requires you to specify the maximum number of characters to read.
3. End of Input:
o cin >> reads until the first whitespace.
o cin.getline() reads until a newline character or until the specified buffer size is reached.

B. The ostream class


The ostream class is responsible for working with the output stream and provides all the
necessary functions for managing chars, strings, and objects such as put, write, cout etc.
#include <iostream>
using namespace std;
intmain()
{
char u;
cin.get(u);
cout.put(u);
}
The C++ ostream class provides a set of functions and operators for writing data as output.
Before using ostream, we need to include the <iostream> header in our program.
#include <iostream>

1) C++ Insertion Operator <<


To write data to the console using ostream, we can use the cout object with the insertion operator << operator.
#include <iostream>
using namespace std;

int main() {

int entered_number;

// write the text "Hello World!" to the screen


cout << "Hello World!";

return 0;
}
Output
Hello World!

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


2) C++ put() Function
The put() function of ostream is primarily used to write characters to the console. For example,
#include <iostream>
using namespace std;

int main() {

char ch = 'A';

// print a character to the console


cout.put(ch);

cout<< endl ;

// print another character to the console


cout.put('C');

return 0;
}
Output
A
C

3) C++ write() Function


The write() function of ostream is generally used to write blocks of data into the console. For example,
#include <iostream>
#include <cstring>

using namespace std;

int main() {

// create a C-string
const char* str = "Hello, World!";

// print the C-string


cout.write(str, strlen(str));

return 0;
}
Output
Hello, World!
Here, we have written a C-string Hello, World to the output stream using the write() function.

C. The ifstream class


When working with the ifstream class in your code, you may come across situations where you need to read
data from a file to proceed with your program. This is where file handling comes into play, and it involves
using stream classes to accomplish this task.
An ifstream object represents an input file stream, which is used to read data from a file. Since an ifstream is a
type of istream, any operations that can be performed on an istream can also be performed on an ifstream.
One common example of an istream is cin, which is used for standard input. Therefore, any operations that
you can perform with cin can also be performed with an ifstream object.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
To use ifstream (and ofstream) in your code, you need to include the fstream header by adding the following
line at the beginning of your program:
#include <fstream>

D. The ofstream class


An ofstream is an output file stream, and works exactly like ifstreams, except for output instead of input.
Once an ofstream is created, opened, and checked for no failures, you use it just like cout:
ofstream fout( "outputFile.txt" );
fout << "The minimum oxygen percentage is " << minO2 << endl;
C++ streams are used in a wide variety of applications, from simple console programs to complex software
systems. Some common use cases for C++ streams include:
Reading and writing to files – C++ streams provide a convenient way to read and write data to and from files.
This can be used to create log files, read configuration files, and more.
Parsing input – C++ streams can be used to parse input data, such as reading data from a CSV file or parsing
command-line arguments.
Debugging – C++ streams can be used to output debugging information, such as the value of variables, to the
console or a file.
Network programming – C++ streams can be used to read and write data over a network connection, such as
when creating a client-server application.

4. File handling
File handling in C++ allows a program to read from and write to files on the disk. It involves using file
streams to interact with files, where data is stored permanently. File handling makes it possible to manage
data between the program and external storage systems, such as text files, binary files, and even databases.

A. What is File Handling?


File handling is a process of reading from and writing data to files. In C++, file handling is performed using
file streams. File streams are classes from the <fstream> library that allow interaction with files in various
modes (text or binary).
Basic operations in file handling include:
• Opening a file: To read from or write to a file, it must first be opened.
• Reading from a file: Extracting data from a file to be processed in the program.
• Writing to a file: Storing data to a file from the program.
• Closing the file: After the operations are done, the file should be closed to free resources.

B. What is a Stream?
In C++, a stream is an abstraction that represents input and output data. It acts as a flow of data between the
program and external storage. There are two main types of streams used in file handling:
1. Input stream (ifstream): Used for reading from a file.
2. Output stream (ofstream): Used for writing to a file.
3. Input/Output stream (fstream): Used for both reading from and writing to a file.
Streams abstract the underlying mechanisms of reading and writing to devices like disks, terminals, and
networks.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
C. Purpose of File Handling
The primary purposes of file handling are:
1. Persistent Data Storage: Files provide a way to save program data between executions, such as
saving user preferences, logs, or configurations.
2. Data Transfer: Files allow sharing data between different programs, users, and systems.
3. Large Data Management: Files are used to handle large datasets that cannot be stored entirely in
memory.

D. Types of Files in C++


1. Text Files:
o Text files store data as plain text. Each character is stored as a sequence of bytes, usually
using ASCII or UTF-8 encoding.
o Example: .txt, .csv
2. Binary Files:
o Binary files store data in a format that is not readable by humans (e.g., raw bytes). These files
are used for storing non-text data, such as images, audio, and other complex data structures.
o Example: .bin, .dat

Feature Text File Binary File


Data Stores data as readable characters Stores data in a non-readable format
Representation (ASCII/UTF-8) (raw binary)
Human Can be read and edited with any text Cannot be easily read with text editors,
Readability editor may require special software
Generally larger due to the use of Typically smaller as it stores data in
File Size
characters for data compact binary format
Character Uses character encoding schemes Uses raw binary data, typically with no
Encoding (ASCII, UTF-8) specific encoding scheme
Data Type Suitable for textual data, such as Used to store any type of data, such as
Handling strings, characters numbers, images, and audio
Has platform-specific EOL characters No specific EOL markers, data is stored
End of Line (EOL)
(e.g., \n or \r\n) as binary values
Faster access and manipulation for
Slower access speed for large files due
Access Speed large files since data is stored directly
to character processing
in binary
Less portable since the binary format is
Highly portable, can be opened on any
Portability platform-dependent (e.g., little-endian
system with a text editor
vs big-endian)
Ease of Data Easy to manipulate text (search, edit) Requires specialized tools or libraries
Manipulation using simple text-processing tools to interpret binary data correctly
Errors during reading or writing can Errors can lead to undetectable data
File Integrity result in visible corruption (e.g., corruption, making it harder to debug
missing characters) or recover

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


E. Access Modes of Files
When opening a file, you can specify the access mode, which determines how the file can be used. Here are
the common file access modes in C++:
1. ios::in: Open a file for reading.
2. ios::out: Open a file for writing (creates a new file or truncates an existing file).
3. ios::app: Open a file for appending (data is written to the end).
4. ios::binary: Open a file in binary mode.
5. ios::trunc: Truncate the file to zero length if it already exists.
6. ios::ate: Open a file and move the file pointer to the end.

F. <fstream> Header File and Its Classes


The file handling functionality is provided by the fstream library, which includes:
• ifstream: Input file stream for reading data from files.
• ofstream: Output file stream for writing data to files.
• fstream: Input/output file stream for both reading and writing.
#include <fstream>

G. File Object Creation


File objects are created using the classes provided by the <fstream> library.
ifstream inFile; // For input file stream
ofstream outFile; // For output file stream
fstream file; // For both input and output

H. File Opening Methods


In C++, files can be opened using the constructor or the open() member function of file stream objects. Both
approaches achieve the same goal—opening a file—but they differ in how they are used.

1) File Opening by Constructor


When you create a file stream object, you can open the file directly using the constructor of the file stream
class (ifstream, ofstream, or fstream). This is a simpler and more concise method, as the file is opened
automatically when the object is created.
Syntax:
ifstream inFile("filename.txt"); // Opens file for reading (ifstream)
ofstream outFile("filename.txt"); // Opens file for writing (ofstream)
fstream file("filename.txt"); // Opens file for both reading and writing (fstream)
In this case, the constructor automatically opens the file when the object is created. The file must be
accessible, and the appropriate access mode should be specified in the constructor.
Example (Opening a file by constructor):

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

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


int main() {
// Open file for reading using the constructor
ifstream inFile("example.txt");

// Check if the file was opened successfully


if (!inFile) {
cout << "Error opening file!" << endl;
return 1; // Exit if file could not be opened
}

string line;
while (getline(inFile, line)) {
cout << line << endl; // Print each line from the file
}

inFile.close(); // Close the file


return 0;
}
In the example above:
• The file "example.txt" is opened for reading when the ifstream object inFile is created.
• If the file is successfully opened, its contents are read and printed to the console.

2) File Opening by open() Member Function


Alternatively, you can use the open() member function of file stream objects to explicitly open a file. This
method provides more flexibility, as it allows you to open a file after the file stream object has already been
created. You can also specify the file access mode in the open() function.
Syntax:
ifstream inFile;
inFile.open("filename.txt", ios::in); // Open for reading
ofstream outFile;
outFile.open("filename.txt", ios::out); // Open for writing
fstream file;
file.open("filename.txt", ios::in | ios::out); // Open for both reading and writing
You can specify file access modes such as ios::in (input), ios::out (output), ios::app (append), ios::binary
(binary mode), etc., as arguments to the open() function.
Example (Opening a file using the open() function):
#include <iostream>
#include <fstream>
using namespace std;

int main() {
// Create an ifstream object (no file opened yet)
ifstream inFile;

// Explicitly open the file for reading


inFile.open("example.txt", ios::in);

// Check if the file was opened successfully


if (!inFile) {
cout << "Error opening file!" << endl;
return 1; // Exit if file could not be opened
}

string line;
while (getline(inFile, line)) {
cout << line << endl; // Print each line from the file
}

inFile.close(); // Close the file


Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
return 0;
}
In this example:
• The ifstream object inFile is first created without opening a file.
• The open() function is called on the object to open "example.txt" for reading.
• The rest of the program reads the file line by line and prints it to the console.
Key Differences Between File Opening by Constructor and Member Function
Feature Opening by Constructor Opening by open() Member Function

Method of The file is opened when the file The file is opened explicitly by calling the open()
Opening stream object is created. function on an existing object.

Shorter syntax. File is opened


Syntax Requires calling open() on an existing object.
directly in the object creation.

Less flexible since the file is opened More flexible, as you can open the file at any
Flexibility
during object creation. point in the program after the object is created.

Re-opening the Can’t re-open the file after the object Can re-open a file multiple times by calling open()
File is created. again.

Access Mode Access modes are specified in the Access modes are specified as arguments to the
Specification constructor. open() function.

Error checking is done immediately


Error Handling Error checking can be done after calling open().
after the object is created.
Which Method to Use?
• Use Constructor Method when you want to open a file immediately upon creating the file stream
object, and you don't need to change the file or access mode afterward.
• Use open() Method when you need to control the file opening process more explicitly, especially if
you want to change the file or access mode at runtime or open the file multiple times.

I. Closing Files
To release the file resources, it is essential to close the file once operations are complete using the close()
method:
inFile.close(); // Close input file
outFile.close(); // Close output file
file.close(); // Close input/output file

J. Reading Data from Files


C++ provides multiple ways to read data from files:
1. Using Extraction Operator (>>): This is commonly used for reading data that can be formatted
(e.g., numbers, strings).

ifstream inFile("input.txt");
int x;
inFile >> x;
2. Using get(): This method reads a single character at a time from the file.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


char ch;
inFile.get(ch); // Read one character from file
3. Using getline(): This reads a full line from the file, including spaces, until a newline is encountered.

string line;
getline(inFile, line); // Read a full line
4. Using read(): This reads raw binary data into a buffer.

char buffer[100];
inFile.read(buffer, sizeof(buffer)); // Read binary data

K. Writing Data to Files


Writing to a file is also done in various ways:
1. Using Insertion Operator (<<): This is commonly used for formatted output (e.g., printing numbers
or strings).

ofstream outFile("output.txt");
outFile << "Hello, World!" << endl;
2. Using put(): This method writes a single character to the file.

outFile.put('A'); // Write one character


3. Using write(): This method writes raw binary data to the file.

char buffer[] = "Binary data";


outFile.write(buffer, sizeof(buffer)); // Write binary data

L. Get and Put Pointer with tellg(), tellp(), seekg(), seekp()


The methods tellg(), tellp(), seekg(), and seekp() are used in C++ to work with file pointers when performing
file input/output operations. These methods are part of the file stream classes (ifstream, ofstream, and fstream)
and allow you to control and retrieve the position of the file pointer during reading and writing operations.

1) tellg() Method
• Purpose: The tellg() method is used to get the current position of the get pointer (input pointer) in a
file. This pointer is used during reading operations.
• Usage: It returns the current position of the get pointer as an integer, which is the byte offset from
the beginning of the file.
• Return Value: It returns a stream position indicator (streampos) that represents the position of the get
pointer.
• Applies to: Input file streams (ifstream and fstream in input mode).

2) tellp() Method
• Purpose: The tellp() method is used to get the current position of the put pointer (output pointer) in
a file. This pointer is used during writing operations.

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


• Usage: It returns the current position of the put pointer as an integer, representing the byte offset
from the beginning of the file.
• Return Value: It returns a stream position indicator (streampos) that represents the position of the put
pointer.
• Applies to: Output file streams (ofstream and fstream in output mode).

3) seekg() Method
• Purpose: The seekg() method is used to move the get pointer (input pointer) to a specific position in
the file. It allows random access while reading a file.
• Usage: You can specify the position to move to from the beginning of the file, from the current
position, or from the end of the file.
• Arguments:
o seekg(offset, direction):
▪ offset: The number of bytes to move the pointer.
▪ direction: This can be one of the following constants:
▪ ios::beg: From the beginning of the file.
▪ ios::cur: From the current position.
▪ ios::end: From the end of the file.
• Return Value: seekg() returns the file stream itself, allowing for chaining of operations.

4) seekp() Method
• Purpose: The seekp() method is used to move the put pointer (output pointer) to a specific position
in the file. It allows random access while writing a file.
• Usage: You can specify the position to move to from the beginning of the file, from the current
position, or from the end of the file.
• Arguments:
o seekp(offset, direction):
▪ offset: The number of bytes to move the pointer.
▪ direction: This can be one of the following constants:
▪ ios::beg: From the beginning of the file.
▪ ios::cur: From the current position.
▪ ios::end: From the end of the file.
• Return Value: seekp() returns the file stream itself, allowing for chaining of operations.
Example:

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

int main() {
// Create and open a file in output mode to write data
ofstream outFile("sample.txt");
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
// Check if file is opened successfully
if (!outFile) {
cout << "Error opening file for writing!" << endl;
return 1;
}

// Write a static string to the file


outFile << "Hello, this is a test file. Welcome to C++ programming!";
outFile.close();

cout << "Data written to file successfully!" << endl;

// Open the file in input mode to read data


ifstream inFile("sample.txt");

// Check if file is opened successfully


if (!inFile) {
cout << "Error opening file for reading!" << endl;
return 1;
}

// Use tellg() to get the current position of the get pointer (before reading)
streampos posBefore = inFile.tellg();
cout << "Initial get pointer position (tellg()): " << posBefore << endl;

// Read the first 5 characters of the file


char ch;
for (int i = 0; i < 5; ++i) {
inFile.get(ch);
cout << ch; // Display each character read
}
cout << endl;

// Get the position of the get pointer after reading 5 characters


streampos posAfter = inFile.tellg();
cout << "Get pointer position after reading 5 characters (tellg()): " << posAfter << endl;

// Use seekg() to move the get pointer back to the beginning of the file
inFile.seekg(0, ios::beg);
cout << "Get pointer moved back to the beginning using seekg()." << endl;

// Read the first character again to verify seekg() worked


inFile.get(ch);
cout << "First character after seekg(): " << ch << endl;

// Open the file in output mode again to write data at a specific position
ofstream outFile2("sample.txt", ios::in | ios::out); // Open file in both input and output mode

if (!outFile2) {
cout << "Error opening file for reading and writing!" << endl;
return 1;
}

// Move the put pointer to position 13 from the beginning using seekp()
outFile2.seekp(13, ios::beg);
cout << "Put pointer moved to position 13 using seekp()." << endl;

// Write new data starting at position 13


outFile2 << "XYZ";

outFile2.close();

cout << "Data written at position 13 using seekp()." << endl;

// Open the file again to verify the changes


Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
inFile.open("sample.txt");
if (!inFile) {
cout << "Error opening file for reading!" << endl;
return 1;
}

// Read the updated content of the file


cout << "File content after seekp() and writing new data:" << endl;
while (inFile.get(ch)) {
cout << ch;
}
cout << endl;

inFile.close();

return 0;
}
Summary of Methods:
Method Purpose Applies to

tellg() Gets the current position of the get pointer (reading) Input streams (ifstream)

tellp() Gets the current position of the put pointer (writing) Output streams (ofstream)

seekg() Moves the get pointer to a specified position (reading) Input streams (ifstream)

seekp() Moves the put pointer to a specified position (writing) Output streams (ofstream)

M. Advanced Member Functions of File Objects


C++ provides several advanced functions for file manipulation:
• eof(): Checks if the end of file has been reached.
• fail(): Checks if the last file operation failed.
• clear(): Resets the error flags on the file stream.
• flush(): Forces the output buffer to be written to the file.

ifstream inFile("example.txt");
if (inFile.eof()) {
cout << "End of file reached." << endl;
}

N. Exception Handling for File Handling


You can use exception handling in file handling to catch errors like failing to open a file.
try {
ifstream inFile("nonexistent.txt");
if (!inFile) {
throw runtime_error("File could not be opened!");
}
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


O. Disk Operations for Files
1. Renaming a File:

if (rename("oldfile.txt", "newfile.txt") != 0) {
perror("Error renaming file");
}
2. Deleting a File:

if (remove("file.txt") != 0) {
perror("Error deleting file");
}
3. Getting File Properties: You can use stat() function to get file properties.

struct stat fileStat;


if (stat("example.txt", &fileStat) == 0) {
cout << "File size: " << fileStat.st_size << " bytes" << endl;
}

P. File Handling Programs


1) Example of Using read() and write() for Objects
We will create a simple class Person, and write objects of this class to a binary file using the write() function,
and then read them back using the read() function.

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

// Define a simple class to represent a Person


class Person {
public:
char name[50];
int age;

// Constructor
Person(const char* n = "", int a = 0) {
strncpy(name, n, sizeof(name)-1);
name[sizeof(name)-1] = '\0';
age = a;
}

// Function to display person data


void display() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};

int main() {
// Create an object of Person
Person p1("Alice", 30);

// Write the object to a binary file using write()


ofstream outFile("person.dat", ios::binary);
if (!outFile) {
cout << "Error opening file for writing!" << endl;

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


return 1;
}

// Write the object to the file


outFile.write(reinterpret_cast<char*>(&p1), sizeof(p1));
outFile.close();

cout << "Object written to file successfully." << endl;

// Create a new object to read data into


Person p2;

// Read the object from the binary file using read()


ifstream inFile("person.dat", ios::binary);
if (!inFile) {
cout << "Error opening file for reading!" << endl;
return 1;
}

// Read the object from the file


inFile.read(reinterpret_cast<char*>(&p2), sizeof(p2));
inFile.close();

cout << "Object read from file successfully." << endl;

// Display the content of the read object


p2.display();

return 0;
}
Output:
Object written to file successfully.
Object read from file successfully.
Name: Alice, Age: 30
Explanation of the Code:
1. Class Definition (Person):
o The Person class contains two members: name (a character array) and age (an integer).
o The constructor initializes the name and age with default values or the ones passed during
object creation.
2. Writing Object to File (write()):
o An object of Person (p1) is created with the name "Alice" and age 30.
o We open the file "person.dat" in binary mode (ios::binary) for writing.
o The write() function is used to write the binary data of the object to the file. We use
reinterpret_cast<char*>(&p1) to treat the Person object as a char* pointer to the raw memory,
and sizeof(p1) ensures that the entire object is written.
o After writing, the file is closed.
3. Reading Object from File (read()):
o Another object p2 is created to store the data read from the file.
o The file "person.dat" is opened again in binary mode, but this time for reading.
o
The read() function is used to read the binary data from the file and store it into the p2 object.
We use reinterpret_cast<char*>(&p2) to treat the p2 object as a char* pointer to receive the
raw data.
Prepared By: - Akshay Arya, Assistant Professor of AIDS Department
o After reading, the file is closed.
4. Displaying the Object:
o The display() function of p2 is called to show the name and age of the person that was read
from the file.
5. Key Points:
• The write() and read() functions are used to perform binary I/O operations.
• These functions work with raw memory, so they are more efficient than other file operations, but they
require careful handling (especially for objects with complex structures or pointers).
• write() takes the raw data of the object and writes it to a file, while read() extracts this data back into
an object.
• For object serialization, we use reinterpret_cast to treat the object as a sequence of bytes.
6. Limitations and Considerations:
1. No Human Readable Format: Data written in binary format is not human-readable. This is fine for
machine-to-machine communication, but you need specific programs to read binary files.
2. Endianness: The byte order (big-endian vs. little-endian) of binary files may be different on different
platforms, so files may not be portable.
3. Complex Objects: If your objects contain pointers or dynamically allocated memory, you need to
handle serialization and deserialization of that memory manually. Simple objects (like the one in the
example) do not face this issue.

2) Example: Write() and Read()


/*Example: read() and write()*/
#include<iostream>
#include<fstream>
using namespace std;
class Student
{
int Roll;
char name[20];
public:
void input()
{
cout<<"\nEnter Roll ";
cin>>Roll;
cout<<"Enter name ";
cin>>name;
}
void output()
{
cout<<"\n Roll No is "<<Roll;
cout<<"\t Name is "<<name;
}
};
int main()
{
fstream file;
file.open("stu.txt",ios::app);
Student A,B;
A.input();
file.write((char*)&A, sizeof(A));
file.close();

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


file.open("stu.txt", ios::in);
while file.read((char*)&B, sizeof(B)))
{
B.output();
}
file.close();
}
Output
Enter Roll 5
Enter Name Shweta
Roll No. is 5 Name is Shweta
3) Example: Search Record by Roll No.
Student.txt (File)
6 Disha
5 Abc
7 Abhishek
8 Ekta
9 Vijay

/*File Searching*/
#include<iostream>
#include<fstream>
using namespace std;
class Student
{
public:
int Roll;
char Name[20];
void input()
{
cout<<"\nEnter Roll No ";
cin>>Roll;
cout<<"Enter Name ";
cin>>Name;
}
void output()
{
cout<<"\nRoll No. is "<<Roll;
cout<<"\tName is "<<Name;
}
};
int main()
{
Student A;
ifstream file1("stu.txt");
int N,C=0;
cout<<"\nEnter Roll No.";
cin>>N;
while(!file1.eof())
{
file1.read((char*)&A, sizeof(A));
if(A.Roll==N)
{
A.output();
C=1;
}
}
if(C==0)
{

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


cout<<"Record Not Found";
}
file1.close();
}
Output
Enter Roll No. 5
Enter Roll No. is 5 Name is Abc

4) Example: Deleting Record


Student.txt (File)
6 Disha
5 Abc
7 Abhishek
8 Ekta
9 Vijay
/*Deleting record from file*/
#include<iostream>
#include<fstream>
#include<stdio.h>
using namespace std;
class Student
{
public:
int Roll;
char Name[20];
void input()
{
cout<<"\nEnter Roll No. ";
cin>>Roll;
cout<<"Enter Name ";
cin>>Name;
}
void output()
{
cout<<"\nRoll No is "<<Roll;
cout<<"\tName is "<<Name;
}
};
int main()
{
Student A;
ifstream file1("stu.txt");
ofstream file2("Temp.txt");
int N;
cout<<"\nEnter Roll No. to Delete ";
cin>>N;
while(!file1.eof())
{
file1.read((char*)&A, sizeof(A));
if(A.Roll!=N)
{
file2.write((char*)&A, sizeof(A));
}
}
file1.close();
file2.close();
remove("stu.txt");
rename("temp.txt", "stu.txt");
file1.open("stu.txt", ios::in);
cout<<"\nRemaining Records are";
while(!file1.eof())

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department


{
file1.read((char*)&A, sizeof(A));
A.output();
}
file1.close();
}
Output
Enter Roll No. to Delete 7
Remaining Records Are
Roll No. is 6 Name is Disha
Roll No. is 8 Name is Ekta
Roll No. is 9 Name is Vijay
5) Example-6: Size of File
/*Checking size of file*/
#include<iostream>
#include<fstream>
using namespace std;
class Student
{
public:
int Roll;
char Name[20];
void input()
{
cout<<"\nEnter Roll No. ";
cin>>Roll;
cout<<"Enter Name ";
cin>>Name;
}
void output()
{
cout<<"\nRoll No is "<<Roll;
cout<<"\tName is "<<Name;
}
};
int main()
{
Student A;
ifstream file("stu.txt");
while(!file.eof())
{
file.read((char*)&A, sizeof(A));
}
cout<<"\n size of file is"<<file.tellg()<<” bytes”;
}
Output-
Size of File is 72 bytes

Prepared By: - Akshay Arya, Assistant Professor of AIDS Department

You might also like