Unit 3 - Notes
CSE202
Unit 3: Data File operations, Constructors, Destructors and File Handling
Part 1: Manager Functions (Constructors and Destructors)
Manager functions are special member functions of a class that facilitate the initialization and destruction of objects. They manage the lifecycle of an object from creation to deletion.
1. Constructors
A Constructor is a special member function that is executed automatically when an object of that class is created. Its primary purpose is to initialize the data members of the object.
Characteristics:
- It has the same name as the class.
- It does not have a return type (not even
void). - It should be declared in the
publicsection (usually). - It can be overloaded.
A. Default Constructor
A constructor that accepts no arguments is called a default constructor. If no constructor is defined explicitly in the class, the C++ compiler automatically provides a default constructor (which does nothing but allocate memory).
class Student {
int id;
public:
// Default Constructor
Student() {
id = 0;
cout << "Object created with default ID: " << id << endl;
}
};
B. Parameterized Constructor
A constructor that accepts parameters to initialize data members with specific values is called a parameterized constructor.
class Point {
int x, y;
public:
// Parameterized Constructor
Point(int i, int j) {
x = i;
y = j;
}
};
// Usage
Point p1(10, 20); // Implicit call
Point p2 = Point(10, 20); // Explicit call
C. Constructor with Default Arguments
Constructors can have default arguments. If specific values are not passed during object creation, default values are used. This can often replace method overloading.
class Box {
int width, height;
public:
// Constructor with default arguments
Box(int w, int h = 10) {
width = w;
height = h;
}
};
// Usage
Box b1(5); // width=5, height=10
Box b2(5, 8); // width=5, height=8
D. Copy Constructor
A copy constructor initializes an object using another object of the same class. It is used to copy data from one object to another.
Syntax: ClassName(const ClassName &old_obj);
Important Note: The argument must be passed by reference. Passing by value would trigger an infinite recursion of copy constructor calls.
class Sample {
int val;
public:
Sample(int v) { val = v; }
// Copy Constructor
Sample(const Sample &s) {
val = s.val;
cout << "Copy constructor called";
}
};
// Usage
Sample obj1(10);
Sample obj2(obj1); // Copy constructor invoked
2. Initializer Lists
An Initializer List is a method of initializing data members within a constructor using a colon (:) syntax before the constructor body.
Why use it?
- Mandatory: For initializing
constmembers andreferencemembers (which must be initialized at creation). - Performance: It initializes members directly, avoiding the overhead of default initialization followed by assignment inside the body.
class Demo {
int x;
const int y; // Must use initializer list
int &z; // Must use initializer list
public:
// Initializer List Syntax
Demo(int a, int b, int &c) : x(a), y(b), z(c) {
// Body can be empty
}
};
3. Destructors
A Destructor is a special member function executed automatically when an object goes out of scope or is explicitly deleted. Its purpose is to release resources (close files, release heap memory) allocated to the object.
Characteristics:
- Same name as the class preceded by a tilde (
~). - No return type and no arguments.
- Cannot be overloaded (only one destructor per class).
- Executed in the reverse order of constructors.
class Test {
int* ptr;
public:
Test() {
ptr = new int[10]; // Allocate memory
}
~Test() {
delete[] ptr; // Deallocate memory
cout << "Destructor called, memory released.";
}
};
Part 2: Data File Operations
File handling allows a program to store data permanently on a secondary storage device. C++ uses a system of streams (sequence of bytes) for file handling.
1. File Stream Classes
To perform file operations, the header file <fstream> must be included.
ifstream: Derived fromistream, used for reading from files (input).ofstream: Derived fromostream, used for writing to files (output).fstream: Derived fromiostream, used for both reading and writing.
2. Opening and Closing Files
Opening Files
There are two ways to open a file:
A. Using Constructor:
ofstream outFile("sample.txt"); // Opens for writing
B. Using open() member function:
ofstream outFile;
outFile.open("sample.txt");
Closing Files
Files should be closed to flush the buffer and release the lock.
outFile.close();
3. Modes of File
File modes determine how the file is opened. They are defined in the ios class and can be combined using the bitwise OR operator (|).
| Mode | Description |
|---|---|
ios::in |
Open for reading (default for ifstream). |
ios::out |
Open for writing (default for ofstream). Overwrites file if it exists. |
ios::app |
Append. All output is added to the end of the file. |
ios::ate |
At End. Moves control to the end of the file upon opening, but allows writing anywhere. |
ios::trunc |
Truncate. If the file exists, its contents are deleted (default if ios::out is used alone). |
ios::binary |
Open in binary mode (treats file as raw byte sequence, no text translation). |
Example:
fstream file;
file.open("data.txt", ios::out | ios::app); // Open for writing in append mode
4. File Stream Functions
Functions used to check the state of the stream:
eof(): Returns true if End-of-File is reached.fail(): Returns true if a logical error occurs (e.g., reading integer but finding a character).bad(): Returns true if a fatal read/write error occurs.good(): Returns true if no error flags are set.
5. Reading and Writing Files (Text Mode)
Sequential Access: Data is processed in order, from start to finish.
Writing: Using the insertion operator (<<).
ofstream out("test.txt");
out << "Hello World" << endl;
out << 100;
out.close();
Reading: Using the extraction operator (>>) or getline().
>>reads until whitespace.getline()reads a whole line.
ifstream in("test.txt");
string s;
while(getline(in, s)) {
cout << s << endl;
}
in.close();
6. Binary File Operations
Binary files store data exactly as it is represented in memory (raw bytes). They are faster and smaller than text files for complex data but are not human-readable.
write(): Used to write blocks of data.read(): Used to read blocks of data.- *`reinterpret_cast<char>`**: Used to cast the address of an object to a character pointer (required by read/write).
Syntax:
file.write((char*)&variable, sizeof(variable));
file.read((char*)&variable, sizeof(variable));
7. Classes, Structures, and File Operations
To save an entire object or structure to a file, we use binary file operations. This process is often called Serialization.
Note on Structures: In C++, struct and class behave similarly regarding file I/O. The code below applies to both.
class Student {
public:
int roll;
char name[20]; // Prefer char arrays over string for binary IO to ensure fixed size
void getData() { cin >> roll >> name; }
void showData() { cout << roll << " " << name << endl; }
};
// Writing Object
void writeObject() {
Student s;
s.getData();
ofstream file("student.dat", ios::binary);
file.write((char*)&s, sizeof(s));
file.close();
}
// Reading Object
void readObject() {
Student s;
ifstream file("student.dat", ios::binary);
if(file.read((char*)&s, sizeof(s))) {
s.showData();
}
file.close();
}
8. Random Access File Processing
Random access allows moving the file pointer to any part of the file directly without reading preceding data. This is crucial for database-like operations.
File Pointers
getpointer: Points to the element to be read in the next input operation.putpointer: Points to the location where the next output operation will write.
Manipulator Functions
seekg(offset, direction): Moves the get (input) pointer.seekp(offset, direction): Moves the put (output) pointer.tellg(): Returns the current position of the get pointer.tellp(): Returns the current position of the put pointer.
Directions (Reference Points)
ios::beg: Beginning of the file.ios::cur: Current position of the pointer.ios::end: End of the file.
Example: Reading the 5th record from a binary file:
void readFifthRecord() {
Student s;
ifstream file("student.dat", ios::binary);
// Formula: (Record Number - 1) * Size of one Record
int pos = (5 - 1) * sizeof(s);
file.seekg(pos, ios::beg); // Move pointer to 5th record
file.read((char*)&s, sizeof(s));
s.showData();
file.close();
}
Example: Determining file size:
ifstream file("data.txt", ios::binary | ios::ate); // Open at end
int size = file.tellg(); // Get position (which corresponds to size in bytes)