In C++, object streams are used for input and output operations involving objects. While basic I/O operations typically deal with simple data types (like int, float, and char), object streams are specifically designed to handle more complex types—i.e., instances of user-defined classes.
The object stream mechanism allows you to serialize (or write) and deserialize (or read) objects to and from files, making it useful for saving and loading object data between different program executions.
Object streams rely on two major components:
std::ofstream for file output, std::ostream for console output)std::ifstream for file input, std::istream for console input)These object streams are derived from the basic stream classes (std::ostream and std::istream) but are extended to support reading and writing objects instead of basic data types.
In order to read and write objects, serialization is required—this means converting the object into a byte stream format suitable for storage in a file and later reconstruction.
To work with object streams in C++, you typically need to overload the << and >> operators for your class so that the data can be read and written correctly.
<< and >> for Object StreamsTo make your class compatible with object streams, you need to overload the insertion operator (<<) for output and the extraction operator (>>) for input.
<<): Used to write (serialize) an object to an output stream (e.g., a file).>>): Used to read (deserialize) an object from an input stream.Here’s how to overload these operators for a class:
#include <iostream>
#include <fstream> // For file streams
using namespace std;
// Define a class called Person
class Person {
private:
string name;
int age;
public:
// Constructor
Person(string n, int a) : name(n), age(a) {}
// Getter functions
string getName() const { return name; }
int getAge() const { return age; }
// Overloading the << operator for serialization (output)
friend ostream& operator<<(ostream& out, const Person& p) {
out << p.name << endl; // Write name to stream
out << p.age << endl; // Write age to stream
return out;
}
// Overloading the >> operator for deserialization (input)
friend istream& operator>>(istream& in, Person& p) {
getline(in, p.name); // Read name from stream
in >> p.age; // Read age from stream
in.ignore(); // Ignore the newline character after age
return in;
}
};
int main() {
// Creating a Person object
Person p1("Alice", 30);
// Writing the object to a file (serialization)
ofstream outFile("person.dat"); // Open file for writing
outFile << p1; // Use overloaded << to write the object
outFile.close();
// Reading the object from the file (deserialization)
Person p2("", 0); // Creating a temporary Person object
ifstream inFile("person.dat"); // Open file for reading
inFile >> p2; // Use overloaded >> to read the object
inFile.close();
// Displaying the deserialized data
cout << "Name: " << p2.getName() << ", Age: " << p2.getAge() << endl;
return 0;
}
Person class with private members name and age.<<) writes the name and age of the Person object to an output stream (such as a file).>>) reads the name and age from an input stream (such as a file) and assigns the values to the corresponding data members of the Person object.In addition to text-based object streams (as shown above), you can also use binary streams to store objects in a more efficient binary format. Binary streams can be faster and more compact than text-based streams because they do not require conversion of data into a human-readable format.
For binary I/O, you use the ofstream and ifstream streams with the ios::binary flag. Here's how you can serialize and deserialize an object to a binary file:
#include <iostream>
#include <fstream>
using namespace std;
// Define a class called Person
class Person {
private:
string name;
int age;
public:
Person(string n = "", int a = 0) : name(n), age(a) {}
// Write the object to a binary file (serialization)
void writeBinary(ostream& out) const {
size_t nameLength = name.size();
out.write(reinterpret_cast<const char*>(&nameLength), sizeof(nameLength)); // Write length of name
out.write(name.c_str(), nameLength); // Write the name itself
out.write(reinterpret_cast<const char*>(&age), sizeof(age)); // Write age
}
// Read the object from a binary file (deserialization)
void readBinary(istream& in) {
size_t nameLength;
in.read(reinterpret_cast<char*>(&nameLength), sizeof(nameLength)); // Read length of name
name.resize(nameLength);
in.read(&name[0], nameLength); // Read the name
in.read(reinterpret_cast<char*>(&age), sizeof(age)); // Read age
}
// Getter functions for name and age
string getName() const { return name; }
int getAge() const { return age; }
};
int main() {
Person p1("Bob", 25);
// Writing to a binary file
ofstream outFile("person_binary.dat", ios::binary);
p1.writeBinary(outFile);
outFile.close();
// Reading from a binary file
Person p2;
ifstream inFile("person_binary.dat", ios::binary);
p2.readBinary(inFile);
inFile.close();
// Displaying the deserialized data
cout << "Name: " << p2.getName() << ", Age: " << p2.getAge() << endl;
return 0;
}
writeBinary() method writes the object to an output stream in a binary format, first writing the length of the string name and then the name itself, followed by the age.readBinary() method reads the object from an input stream in binary format.reinterpret_cast is used to handle the conversion between data types (e.g., converting an integer to a byte representation for storage).Advantages:
<< and >> operators, you can customize how each object is serialized and deserialized.Disadvantages:
<< and >> operators for each class you want to work with object streams.<< and >> operators, you control how your class’s data is written and read.Open this section to load past papers