0% found this document useful (0 votes)
16 views91 pages

Module 5 Oops

Uploaded by

ankithavv13
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views91 pages

Module 5 Oops

Uploaded by

ankithavv13
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 91

Module 5

I/O System Basics, File I/O


C++ streams
Stream is an abstraction that represents a sequence of bytes flowing
from a source to destination.
Streams are used to handle input and output operations making it
easier to read from and write to various devices or files.

Stream is like a medium between keyboard and file or between file


and screen.
C++ stream classes
• Standard C++ provides support for its I/O system in <iostream>.
• In this header there are set of classes which support I/O operations.
• These classes are template classes (template classes are those which
can operate on any type of data)
• As we know template classes can be defined once and specific
instances of it can be created..
• So there are mostly 2 instances of the I/O template classes: one for 8
bit characters and one for wide characters (like UTF 16 and UTF 32)
• SO the template classes and its versions in 8 bit and wide characters are
as follows
C++ predefined streams
• Cin
• Cout
• Cerr : to display error
• Clog : used to write into log file ( few program execution instructions)
Formatted i/o
• It is used to insert or print values in a specified format.
• For example: we can control the number of digits to be displayed
after the decimal point in a floating point number.
• formatted I/O is used to control the way data is displayed, allowing
for more readable and organized output.
• To set flag use setf, to unset use unsetf.
• Syntax
• cout.setf(ios::flag)
SHOWPOS (show positive) FLAG
Using ios::showpos forces the output stream to display a plus sign for positive
numbers, enhancing the clarity of the sign of the values in the output.

#include <iostream>
Using namespace std;

int main() {
int positiveNumber = 42;
int negativeNumber = -42;
double positiveFloat = 3.14;
double negativeFloat = -3.14;
cout << "Without showpos:" << endl;
cout << "Positive integer: " << positiveNumber << endl;
cout << "Negative integer: " << negativeNumber << endl;
cout << "Positive float: " << positiveFloat << endl;
cout << "Negative float: " << negativeFloat << endl;
cout.setf(ios::showpos); // Enable showpos

cout << "With showpos:" << endl;


cout << "Positive integer: " << positiveNumber << endl;
cout << "Negative integer: " << negativeNumber << endl;
cout << "Positive float: " << positiveFloat << endl;
cout << "Negative float: " << negativeFloat << endl;

cout.unsetf(ios::showpos); // Disable showpos

return 0;
}
• Output
Without showpos:
Positive integer: 42
Negative integer: -42
Positive float: 3.14
Negative float: -3.14

With showpos:
Positive integer: +42
Negative integer: -42
Positive float: +3.14
Negative float: -3.14
SHOWPOINT FLAG
• By setting ios::showpoint, the output stream forces the display of
the decimal point and the appropriate number of trailing zeros to
maintain a consistent number of digits after the decimal point.
• This ensures a uniform display format, which can be particularly
useful in contexts where consistency in the representation of floating-
point numbers is important.
• #include <iostream>
• Using namespace std;

• int main() {
• double number1 = 42.0;
• double number2 = 42.12;

• cout << "Without showpoint:" << std::endl;


• cout << "Number1: " << number1 << std::endl;
• cout << "Number2: " << number2 << std::endl;

• cout.setf(ios::showpoint); // Enable showpoint


• cout << "With showpoint:" << std::endl;
• cout << "Number1: " << number1 << std::endl;
• cout << "Number2: " << number2 << std::endl;

• cout.unsetf(ios::showpoint); // Disable showpoint

• return 0;
• }
OUTPUT
Without showpoint:
Number1: 42
Number2: 42.12

With showpoint:
Number1: 42.0000
Number2: 42.1200
• By default showpoint displays 6 numbers when used with digital
point numbers .
• You can both decrease and increase the number of digits displayed
after the decimal point by adjusting the precision using the precision
method.
#include <iostream>

int main() {
double number1 = 42.0;
double number2 = 42.12;

cout << "Without showpoint:" << endl;


cout << "Number1: " << number1 << endl;
cout << "Number2: " << number2 << endl;

cout.setf(ios::showpoint); // Enable showpoint


cout.precision(6); // Set precision to 6 digits after the decimal point
cout << "With showpoint and precision(6):" <<endl;
cout << "Number1: " << number1 << endl;
cout << "Number2: " << number2 << endl;

cout.unsetf(ios::showpoint); // Disable showpoint

return 0;
}
• OUTPUT
• Without showpoint:
• Number1: 42
• Number2: 42.12

• With showpoint and precision(6):


• Number1: 42.000000
• Number2: 42.120000
Program with precision (without showpoint):
• #include <iostream>

• int main() {
• double number1 = 42.0;
• double number2 = 42.12345;

• cout << "Without showpoint:" << endl;


• cout << "Number1: " << number1 << endl;
• cout << "Number2: " << number2 << endl;

• cout.precision(3); // Set precision to 3 digits after the decimal point


cout << "With precision(3) only:" << std::endl;
cout << "Number1: " << number1 << std::endl;
cout << "Number2: " << number2 << std::endl;

return 0;
}
OUTPUT
Without showpoint:
Number1: 42
Number2: 42.1235

With precision(3) only:


Number1: 42
Number2: 42.1

When you set precision(3) without showpoint, the number 42.12345 is


displayed as 42.1 because precision affects how many digits are displayed
INCLUDING the decimal point and rounds the number accordingly.
If you want to ensure the full precision is displayed, including trailing zeros, you
would need to use showpoint in conjunction with precision.
Flags:
Definition: Flags in C++ streams (like std::ios_base::fmtflags, std::
ios_base::iostate, std::ios_base::openmode) represent state information
that persists across multiple operations on the stream.

Scope: They affect the overall behavior of the stream until explicitly
changed or cleared.

Usage: Flags are typically set using member functions like setf() (to set
flags) or unsetf() (to clear flags)
Overloaded form of setf()
• you can design an overloaded form of the setf() function to clear the
previous tag before setting a new one. This can be more convenient
and maintainable compared to using unsetf() and setf() separately.
• Syntax:
• Fmtflags setf(fmtflags flags1, fmtflags flag2);
• Here the flag2 is first cleared and flag1 is set.
Example:
#include <iostream>
Using namespace std;

int main() {
cout.setf(ios::showpoint); // Set showpoint
cout << 123.0 ; // Outputs: 123.000

cout.setf(ios::showpos, ios::showpoint); // Unset showpoint and set


showpos
cout << 123; // Outputs: +123

return 0;
}
Examining the formatting flags
• This is used to check which formatting flags are set in the cout
stream and print a binary representation of these flags.
• There are 16 flags in the following order in ios::fmtflags..
• boolalpha: Print bool values as "true" or "false".
• showbase: Print the base (e.g., 0x for hex).
• showpoint,showpos,skipws,unitbuf,uppercase,dec,oct,hex etc…
#include<iostream>
int main() {
// Set some format flags

// Show condition of format flags


showflags();

return 0;
}
void showflags() {
ios::fmtflags f;
f = cout.flags(); // Get the current flag settings

// Check each flag


for (long i = 0x4000; i; i >>= 1) {
if (i & f) {
cout << '1';
} else {
cout << '0';
}
}
cout << "\n";
}
• this code starts from 0*4000 in hex means 1000000000000000 in
binary ..
• it checks if bit is in current position that is i and checks if the first flag is
set then prints 1 there..
• it continue this for 16 bit positions because there are 16 fmtflags...
after each iteration it does i>>1 means it shifts i by one position..
I/O Manipulators:
Definition: Manipulators in C++ are functions or objects that modify the
state or formatting of the stream for the next input or output operation.
Scope: They are applied locally and transiently to specific output or
input operations.
Usage: Manipulators are typically used with the insertion (<<) and
extraction (>>) operators to modify the behavior of the stream for a
single line or operation.

While using I/O manipulators with <<, >> operators in a line, we need to
include <iomanip> headerfile.
#include<iostream>
#include<iomanip>

Void main()
{
Int val=2343;
Cout<<setfill(‘?’) << setw(10) << val;
}

OUTPUT:
??????2343
File Operations
• Opening and closing a file
• Reading and writing text files.
Fstream and the file classes
• In C++, the fstream library provides classes for file input and output
operations. Here’s a brief overview of the classes and their purposes:
• ifstream (input file stream): This class is used for reading from files.
• ofstream (output file stream): This class is used for writing to files.
• fstream (file stream): This class is used for both reading from and
writing to files.
• ifstream is for read-only operations.ofstream is for write-only
operations.fstream is for both read and write operations.
Opening and closing a file
OPENING FILE FOR READING IS WRITTEN AS
Ifstream mystream(“myfile”);
Eg: ifstream in(“inventory”);

OPENING FILE FOR WRITING IS WRITTEN AS


Ofstream mystream(“myfile”);
Eg: Ofstream out(“inventory”);
If open fails, the stream will evaluate to false when used in a Boolean
expression

If(!mystream) {
Cout<<“cannot open file”;
}

CLOSING A FILE
Mystream.close;
• We can also set mode while opening a file.
• Mode specifies how we want to read or write into a file.
• Most common modes are
• Ios::app, ios::ate, ios::trunc..

• Which can be specified as


• Ofstream mystream(“myfile”,ios::trunc);
• ios::app (append mode):When a file is opened with ios::app, all write
operations are performed at the end of the file, regardless of the
current position of the file pointer.
• This means every time you write to the file, the data is appended to
the end.
• The file pointer is automatically moved to the end of the file before
every write operation.
• This mode is useful when you want to add new data to an existing file
without modifying its current content.
• used with write only or out stream.
• ios::ate : Which means at end.
• When a file is opened with ios::ate, the file pointer is initially positioned
at the end of the file.
• However, unlike ios::app, you can move the file pointer to different
positions within the file for subsequent read or write operations.
• This mode allows you to write or read from any position in the file after
the initial seek to the end.
• This mode is useful when you want to start with the file pointer at the
end but still need the flexibility to read from or write to other parts of
the file.
• used with read and write.
• The ios::trunc mode in C++ is used to open a file and immediately
truncate its contents to zero length if the file already exists.
• This means any existing data in the file will be erased as soon as the
file is opened.
• The file is then ready for new data to be written to it.
• Used with write only or out
Reading and writing text files
• Its very easy to read from or write to a file. Simply use << and >>
operators the same way you do when performing console i/o, except
that instead of using cin and cout, substitute a stream that is linked
to a file.
• For example this program creates a short inventory file that contains
eah item’s name and its cost.
#include<iostream>
#include<fstream>

void main()
{
Ofstream out(“INVENTORY”);

If(!out)
{
Cout<<“cannot open file”;
}
Out<<“radios”<<2000;
Out<<“tv”<<15000;
Out<<“fan”<<5000;

Out.close;
}
• To read the data which is written to that inventory file, use
#include<iostream>
#include<fstream>
void main()
{
ifstream in(“INVENTORY”);
If(!in)
{
Cout<<“cannot open file”;
}
Char item;
Int cost;

In>>item>>cost;
Cout<<item<<cost;
In>>item>>cost;
Cout<<item<<cost;
In>>item>>cost;
Cout<<item<<cost;

In.close();
}
Following Program used to write into a file and then read from it.
Syntax used is
fstream file("filename", ios::in|ios::out);

#include <iostream>
#include <fstream
int main()
{
Char item;
Int cost;

fstream file("filename", std::ios::in | std::ios::out);


if (!file)
{
cout<< "Failed to open the file.\n";
return 1;
}
• // Writing data to the file
• file << "radio " << 35 ;
• file << "fan " << 40 ;
• file << "tv " << 50 ;
• // Reset file position to the beginning
• file.seekg(0);
// Reading data from the file
while (file >> item >> cost)
{
cout << item << cost ;
}
// Close the file
file.close();
}
Exception handling Fundamentals
Exception handling is a way to manage errors and unexpected
situations that arise while a program is running. Instead of allowing the
program to crash or produce incorrect results, exception handling lets
you "catch" errors, deal with them appropriately, and continue running
the program if possible.
Exception handling provides a structured approach to dealing with
errors, making it easier to separate error-handling code from normal
program logic. This separation improves code readability and
maintainability, especially in complex systems where errors may occur
in various parts of the program.
Basics of Exception Handling in C++
try Block:
The code that might cause an exception is placed inside a try block.

throw Statement:
When an error occurs, you can use the throw statement to signal an
exception.

catch Block:
The code that handles the exception is placed inside a catch block. This
block follows the try block
• General form of try and catch statement is shown here
Example:
#include <iostream>
void divide(int numerator, int denominator)
{
try
{
if (denominator == 0)
{
throw denominator; // Throw the denominator value if it's zero
}
int result = numerator / denominator;
cout << "Result of division: " << result ;
}
catch (int error)
{
cerr << "Exception caught: Division by zero error. Denominator was: " << error ;
}
}
void main()
{
divide(10, 2); // Normal division
divide(8, 0); // Division by zero
divide(12, 3); // Normal division
}
ONE MORE EXAMPLE
#include <iostream>
void checkNumber(int number)
{
try
{
if (number < 0)
{
throw number; // Throw the negative number
}
cout << "Number is: " << number ;
}
catch (int error)
{
cerr << "Exception caught: Negative number not allowed. Value was: " << error;
}
}
void main()
{
checkNumber(10); // Normal positive number
checkNumber(-5); // Negative number
checkNumber(20); // Another positive number
}
Catching Class types
An exception can be of any type, including class types that you create.
Actually, in real-world programs, most exceptions will be class types rather
than built-in types. Perhaps the most common reason that you will want
to define a class type for an exception is to create an object that describes
the error that occurred. This information can be used by the exception
handler to help it process the error. The following example demonstrates
this.
#include <iostream>
class MyException
{
public:
Char str_what[80];
Int what;

MyException( )
{
*str_what=0;
What = 0;
}

MyException(char *s, int e)


{
Strcpy(str_what, s);
What = e;
}
};
Int main()
{
Int i;
try
{
Cout<<“enter a positive number”;
Cin>>i;
If(i<0)
Throw MyException(“Not positive”,i);
}
Catch (MyException e)
{
Cout<<e.str_what;
Cout<<e.what;
}
Return 0;
}
• The program prompts the user for a positive number. If a negative
number is entered, an object of the class MyException is created that
describes the error. Thus, MyException encapsulates information
about the error. This information is then used by the exception
handler. In general, you will want to create exception classes that will
encapsulate information about an error to enable the exception
handler to respond effectively.
Using multiple catch statements
• There can be multiple catch statements associated with a try. But each
‘catch’ must catch a different type of exception.
• General form:
Example for Using multiple catch statements
#include <iostream>
using namespace std;
// Different types of exceptions can be caught.
void Xhandler(int test)
{
try
{
if (test == 1)
throw test;
else if (test == 2)
throw test;
else if (test == 0)
throw "Value is zero";
else
throw test;
}
catch (int i)
{
cout << "Caught Exception #: " << i ;
}
catch (string *str)
{
cout << "Caught a string: ";
cout << str ;
}
}
int main()
{
cout << "Start";
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << "End";
return 0;
}
Output:
Start
Caught Exception #: 1
Caught Exception #: 2
Caught a string: Value is zero
Caught Exception #: 3
End
Handling derived class exceptions
• You need to be careful how you order your catch statements when
trying to catch exception types that involve base and derived classes
because a catch clause for a base class will also match any class
derived from that base.
• Thus, if you want to catch exceptions of both a base class type and a
derived class type, put the derived class first in the catch sequence.
• If you don’t do this, the base class catch will also catch all derived
class exceptions.
#include <iostream>
using namespace std;
// Base class
class Shape
{
public:
virtual void print()
{
cout << "Shape";
}
};
// Derived class Rectangle
class Rectangle : public Shape
{
public:
void print()
{
cout << "Rectangle";
}
};
// Derived class Circle
class Circle : public Shape
{
public:
void print()
{
cout << "Circle";
}
};
int main()
{
try
{
Circle c;
throw c;
}
catch (Shape &s)
{
cout << "Caught a Shape.";
}
catch (Rectangle &r)
{
cout << "Caught a Rectangle.";
}
catch (Circle &c)
{
cout << "Caught a Circle.\n";
}
return 0;
}
• When an exception of type Circle is thrown, the program tries to find a
matching catch block.
• It finds the catch (Shape& s) block first. Since Circle is a type of Shape (due
to inheritance), this catch block catches the exception.
• Even though there is a more specific catch block i.e catch(Circle& c) further
down, the program does not reach it because the first matching catch block
(Shape) handles the exception.
• Therefore, placing the catch block for Shape first in this example would catch
exceptions of both Shape and its derived classes (Rectangle and Circle),
making the catch block for Circle (the most specific type in this context)
unreachable.
• To handle exceptions correctly and ensure that each type is caught
appropriately: Always list catch blocks from the most derived type to the
base type.
• This way, each exception will be caught by the most specific catch block that
matches its type..
Exception handling options
Catching All Exceptions
In some circumstances you will want an exception handler to catch all
exceptions instead of just a certain type.
This is easy to accomplish.
Simply use this form of catch
catch(...)
{
// process all exceptions
}
The following program illustrates catch
// This example catches all exceptions.
#include <iostream>
using namespace std;
void Xhandler (int test)
Try
{
if (test==0) throw test; // throw int
if (test==1) throw 'a'; // throw char
if (test==2) throw 123.23; // throw double
}
catch(...)
{
// catch all exceptions.
cout << "Caught One!";
}
}
int main()
{
cout << "Start";
Xhandler (0);
Xhandler (1);
Xhandler (2);
cout << "End";
Return 0;
}
Output
Start
Caught one
Caught one
Caught one
End
You can also use it when you want to catch an exception and
want to rely on catch(…) for all other exceptions
#include <iostream>
using namespace std;
void Xhandler (int test)
Try
{
if (test==0) throw test; // throw int
if (test==1) throw 'a'; // throw char
if (test==2) throw 123.23; // throw double
}
Catch(int i)
{
Cout<<“caught an integer exception”;
}
catch(...)
{
// catch all exceptions.
cout << "Caught One!";
}
}
int main()
{
cout << "Start";
Xhandler (0);
Xhandler (1);
Xhandler (2);
cout << "End";
Return 0;
}
Output
Start
Caught an integer exception
Caught one
Caught one
End
• Restricting Exceptions
• You can restrict the type of exceptions that a function can throw outside
of itself.
• In fact, you can also prevent a function from throwing any exceptions
whatsoever.
• To accomplish these restrictions, you must add a throw clause to a
function definition.
• The general form of this is shown here:
• ret-type func-name(arg-list) throw(type-list)
• {
• //…
• }
• Here, only those data types contained in the comma-separated type-
list may be thrown by the function. Throwing any other type of
expression will cause abnormal program termination. If you don't
want a function to be able to throw any exceptions, then use an
empty list.

• Attempting to throw an exception that is not supported by a function


will cause the standard library function unexpected() to be called. By
default, this causes abort() to be called, which causes abnormal
program termination. However, you can specify your own unexpected
handler.
• In this program, the function Xhandler() may only
throw integer, character and double exceptions.
If it attempts to throw any other type of
exception, an abnormal program termination will
occur.
Rethrowing an exception
• If you wish to rethrow an expression from within an exception
handler, you may do so by calling throw, by itself, with no exception.
This causes the current exception to be passed on to an outer try/
catch sequence.
• while writing code, you might initially handle an exception using a
basic try and catch block. Later, as you continue writing and refining
your code, a more advanced solution for handling the exception
might come to mind. Instead of going back to rewrite your initial
catch block, you can simply rethrow the exception in your initial catch
block and then add a new, more advanced catch statement elsewhere
in your code to handle it more thoroughly.
#include <iostream>
using namespace std;
void Xhandler()
{
try
{
throw "hello"; // throw a char*
}
catch(const char *)
{ // catch a char*
cout << "Caught char* inside Xhandler";
throw; // rethrow char* out of function
}
}
int main()
{
cout << "Start";
Try
{
Xhandler();
}
catch(const char *)
{
cout << "Caught char* inside main";
}
cout << "End";
return 0;
}
Output
This program displays this output:
Start
Caught char* inside Xhandler
Caught char* inside main
End
Setting the Terminate and Unexpected
Handlers
• some exceptions which the try and catch also cannot handle will
make the program to abort but to make the people understand why
it's aborted we have to write some error message and we can do that
by redefining terminate and unexpected..
#include <iostream>
#include <exception>

void custom_terminate() {
cerr << "Termination due to unhandled exception." ;
abort();
}

void custom_unexpected() {
cerr << "Unexpected exception occurred.";
terminate();
}

void handler(int test) throw(char) {


if (test == 'a')
throw test;
}
int main() {
set_terminate(custom_terminate);
set_unexpected(custom_unexpected);

try {
handler(0);
}
catch (int i) {
cout << "Caught an integer: " << i ;
}
catch (char c) {
cout << "Caught a char: " << c ;
}
catch (double d) {
cout << "Caught a double: " << d ;
}

cout << "End";


return 0;
}

You might also like