Examples of saving/reading class objects. Serialization
This topic contains examples of serializing class objects. In the most general case, serialization is the property of an object to store its state in a file stream and (on demand) restore it.
Contents
- 1. An example of developing a class that contains the means of writing to a file and reading from a file. The class implements an array of numbers of type double*
- 2. An example of writing/reading a class object containing fields of the string type
- 3. An example of writing/reading a class object containing nested objects of another class
- Related topics
Search other resources:
1. An example of developing a class that contains the means of writing to a file and reading from a file. The class implements an array of numbers of type double*
The example shows the property of a class instance to save its state in a file and restore it from a file. The object state is the current value of the internal data (internal fields) of the object.
A class has been developed that contains the following components:
- A – array of numbers of double type;
- count – current number of elements in the array;
- constructor ArrayNumbers(double*, int) – initializes the internal array with external data;
- ArrayNumbers() constructor – creates a zero-length array;
- copy constructor ArrayNumbers(const ArrayNumbers&);
- operator function operator=(const ArrayNumbers&);
- destructor ~ArrayNumbers();
- method Print() – displays the contents of the current instance;
- method SaveToFile(char*) – writes the current instance to a file;
- method ReadFromFile(char*) – reads the current instance from a file.
#include <iostream> #include <fstream> using namespace std; // Array of numbers class ArrayNumbers { private: // Internal fields double* A; int count; public: // Constructors ArrayNumbers(double* _A, int _count) { try { count = _count; A = new double[count]; for (int i = 0; i < _count; i++) A[i] = _A[i]; } catch (bad_alloc e) { cout << e.what() << endl; } } // Constructor without a parameters ArrayNumbers() { count = 0; } // Copy constructor ArrayNumbers(const ArrayNumbers& obj) { try { count = obj.count; A = new double[count]; for (int i = 0; i < count; i++) A[i] = obj.A[i]; } catch (bad_alloc e) { cout << e.what() << endl; } } // Copy operator ArrayNumbers& operator=(const ArrayNumbers& obj) { // Release pre-allocated memory if (count > 0) delete[] A; try { count = obj.count; A = new double[count]; for (int i = 0; i < count; i++) A[i] = obj.A[i]; } catch (bad_alloc e) { cout << e.what() << endl; } } // Destructor ~ArrayNumbers() { if (count > 0) delete[] A; } // Function to display the contents of the current instance void Print(string msg) { cout << msg; cout << ": A => { "; for (int i = 0; i < count; i++) { cout << A[i] << " "; } cout << "}" << endl; } // Serialization methods // Writing the current instance to a file bool SaveToFile(const char* filename) { // 1. Create an instance of the ofstream class ofstream outF(filename, ios::out | ios::binary); if (!outF) return false; // 2. Write number of elements in array outF.write((char*)&count, sizeof(count)); // 3. Write the array for (int i = 0; i < count; i++) { outF.write((char*)&A[i], sizeof(A[i])); } // 4. Close the file outF.close(); // 5. Return true return true; } // Reading an array from a file and writing to the current instance bool ReadFromFile(const char* filename) { // 1. Create an instance of the ifstream class, attempting to open a file ifstream inF(filename, ios::in | ios::binary); if (!inF) return false; // 2. First release pre-allocated memory for array if (count > 0) delete[] A; // 3. Read the number of elements in array inF.read((char*)&count, sizeof(int)); try { // 4. Attempt to allocate memory for the elements of array A = new double[count]; } catch (bad_alloc e) { // 5. If the attempt is unsuccessful, then exit the function cout << e.what(); inF.close(); // close the file return false; } // 6. Read the array element by element double x; for (int i = 0; i < count; i++) { inF.read((char*)&x, sizeof(double)); // read 1 element of type double A[i] = x; } // 7. Close the file stream inF.close(); // 8. Exit with code true - the file has been read return true; } }; void main() { // 1. Create a test array double AD[] = { 2.8, 3.5, 1.4, 7.0, 2.5 }; // 2. Create an instance A1 of the ArrayNumbers class and write it to the file file1.bin ArrayNumbers A1(AD, 5); A1.Print("A1"); // A1 = { 2.8, 3.5, 1.4, 7.0, 2.5 } A1.SaveToFile("file1.bin"); // 3. Create an instance A2 of the ArrayNumbers class that contains a null array // and fill it with data from the file file1.bin ArrayNumbers A2; A2.Print("A2"); // A2 = { } A2.ReadFromFile("file1.bin"); A2.Print("A2"); // A2 = { 2.8, 3.5, 1.4, 7.0, 2.5 } }
Program result
A1: A => { 2.8 3.5 1.4 7 2.5 } A2: A => { } A2: A => { 2.8 3.5 1.4 7 2.5 }
⇑
2. An example of writing/reading a class object containing fields of the string type
To write a string of type string to a binary file, you need to perform the following sequence of actions:
- get the length of the string (number of characters). This is an integer of type int;
- write the length of the line to the file;
- write each character of the string to a file using a loop.
To read a line from a file into an object of type string, you need to follow the following sequence:
- read the length of a line from a file as int type;
- in the loop, read the entire line character by character into some memory area or use the addition of a character to the end of the line in each iteration of the loop.
The example implements the serialization of an object of type BOOK. The BOOK class describes a book containing the following fields:
- author – the name of the author of the book. This field is of type string;
- title – title of the book, field of the string type;
- year – publication year;
- price – price of the book.
The class also contains a number of methods for operating with data about the book and saving/reading this data:
- BOOK() – parameterized constructor;
- Author() – a method that returns the name of the author of the book;
- Title() – title of the book;
- Year() – publication year;
- Price() – price of the book;
- SaveToFile() – method that writes the current value of internal fields to a file;
- ReadFromFile() – method that reads field values from a file.
The text of the demo program is as follows.
#include <iostream> #include <fstream> using namespace std; // Class describing the book class BOOK { private: // Internal fields string author; // author string title; // book title int year; // publishing year float price; // cost public: // Constructor BOOK(string _author, string _title, int _year, float _price) { author = _author; title = _title; year = _year; price = _price; } // Methods for reading data string Author() { return author; } string Title() { return title; } int Year() { return year; } float Price() { return price; } // Method that displays field values (internal state of object) void Print(string msg) { cout << msg << endl; cout << "Author = " << author << endl; cout << "Title = " << title << endl; cout << "Year = " << year << endl; cout << "Price = " << price << endl; cout << "-----------------------------" << endl; } // Methods for writing/reading current data (serialization) bool SaveToFile(const char* filename) { // 1. Create an instance of the ofstream class ofstream outF(filename, ios::out | ios::binary); // 2. Checking if the file has been created // if not created then exit with code false if (!outF.is_open()) return false; // 3. Write fields data // 3.1. Field author of type string // 3.1.1. Determine the length of a string of type string int len = author.length(); // 3.1.2. Write the length of the author string outF.write((char*)&len, sizeof(int)); // 3.1.3. Write each character of a string in a loop for (int i = 0; i < author.length(); i++) outF.write((char*)&author[i], sizeof(author[i])); // 3.2. The title field of string type // 3.2.1. Get string length len = title.length(); // 3.2.2. Write the length of the title string outF.write((char*)&len, sizeof(int)); // 3.2.3. Write a string character by character for (int i = 0; i < title.length(); i++) outF.write((char*)&title[i], sizeof(title[i])); // 3.3. The year field of type int outF.write((char*)&year, sizeof(int)); // 3.4. The price field of float type outF.write((char*)&price, sizeof(float)); // 4. Close the file outF.close(); // 5. Return code return true; } // Reading an array from a file and writing to the current instance bool ReadFromFile(const char* filename) { // 1. Create an instance of the ifstream class ifstream inF(filename, ios::in | ios::binary); // 2. Checking if a file was opened successfully if (!inF.is_open()) return false; // 3. Reading the fields of an object // 3.1. The author field // 3.1.1. Read the number of elements in the field author int len; inF.read((char*)&len, sizeof(int)); // 3.1.2. Read a string in a loop char c; author = ""; for (int i = 0; i < len; i++) { inF.read((char*)&c, sizeof(c)); author += c; } // 3.2. The title field of string type // 3.2.1. Get the length of string inF.read((char*)&len, sizeof(int)); // 3.2.2. Read a string in a loop title = ""; for (int i = 0; i < len; i++) { inF.read((char*)&c, sizeof(c)); title += c; } // 3.3. The field year of int type inF.read((char*)&year, sizeof(int)); // 3.4. The price field of float type inF.read((char*)&price, sizeof(float)); // Close the file inF.close(); // Return code return true; } }; void main() { // 1. Create the object of BOOK type BOOK obj1("Author", "Title", 2000, 2.55); // 2. Save the obj1 object obj1.Print("obj1"); // 3. Save to file obj1 => "obj1.bin" obj1.SaveToFile("obj1.bin"); // 4. Create another object of type BOOK BOOK obj2("--", "--", 3000, 10.88); obj2.Print("obj2"); // 5. Read data from file obj1.bin to obj2 object // "obj1.bin" => obj2 obj2.ReadFromFile("obj1.bin"); // 6. Print the object obj2.Print("obj2 <= obj1.bin"); }
Program result
obj1 Author = Author Title = Title Year = 2000 Price = 2.55 ----------------------------- obj2 Author = -- Title = -- Year = 3000 Price = 10.88 ----------------------------- obj2 <= obj1.bin Author = Author Title = Title Year = 2000 Price = 2.55 -----------------------------
⇑
3. An example of writing/reading a class object containing nested objects of another class
This example considers the case when objects (instances) of another class are declared in a class, and these objects need to be correctly saved and read. According to the above example, you can save and read structure variables (structures).
To save nested objects in a class, you need to directly get the data of these objects in the form of primitive types (int, doulbe, char, etc.).
When writing and reading data (internal fields) of objects, it is important to follow the following rule:
- the sequence of the data to be written must match the sequence of the data to be read. So, for example, if data x, y, z are written, then in the same order these data should be read.
The example demonstrates saving an instance of the Line class, which has two built-in objects of type Point. For writing/reading in the Line class, two methods SaveToFile() and ReadFromFile() are respectively implemented.
The text of the demo program is as follows
#include <iostream> #include <fstream> using namespace std; // Class describing a point on a coordinate plane class Point { private: // Internal fields double x, y; public: // Constructor Point(double _x, double _y) : x(_x), y(_y) { } // Access methods void SetXY(double _x, double _y) { x = _x; y = _y; } double X() { return x; } double Y() { return y; } // Method that displays x,y values void Print(string msg) { cout << msg << " => x = " << x << ", y = " << y << endl; } }; // A class that describes a line class Line { private: Point p1; // first point Point p2; // second point public: // Constructor Line(double _x1, double _y1, double _x2, double _y2) : p1(_x1, _y1), p2(_x2, _y2) { } // Access methods Point P1() { return p1; } Point P2() { return p2; } // Method that displays the coordinates of the points of the line void Print(string msg) { cout << msg << endl; p1.Print("p1"); p2.Print("p2"); cout << "-----------------------" << endl; } // Methods that write/read data bool SaveToFile(const char* filename) { // 1. Create an instance of outF that is associated with the file filename, // here: // - ios::out - the file is opened for writing; // - ios::binary - the file is opened in binary mode. ofstream outF(filename, ios::out | ios::binary); // 2. Checking if a file has been created if (!outF.is_open()) return false; // 3. Write data of fields p1, p2 of type Point double x1 = p1.X(); double y1 = p1.Y(); double x2 = p2.X(); double y2 = p2.Y(); outF.write((char*)&x1, sizeof(x1)); outF.write((char*)&y1, sizeof(y1)); outF.write((char*)&x2, sizeof(x2)); outF.write((char*)&y2, sizeof(double)); // it is possible so // 4. Close the file outF.close(); } bool ReadFromFile(const char* filename) { // 1. Create an instance of inF that is associated with the file filename ifstream inF(filename, ios::in | ios::binary); // 2. Checking if a file was opened successfully if (!inF.is_open()) return false; // 3. Reading the line coordinates into temporary variables double x1, y1, x2, y2; // the reading order of the fields must match the writing order inF.read((char*)&x1, sizeof(double)); inF.read((char*)&y1, sizeof(double)); inF.read((char*)&x2, sizeof(x2)); inF.read((char*)&y2, sizeof(y2)); // 4. Writing coordinates to the internal fields of the current object p1.SetXY(x1, y1); p2.SetXY(x2, y2); // 5. Close the file inF.close(); } }; void main() { // 1. Create the first line and output it Line L1(2.5, 3.8, 4.1, 7.9); L1.Print("L1"); // 2. Create a second line and output it Line L2(1.0, 1.0, 2.0, 2.0); L2.Print("L2"); // 3. Write first line to file "line.bin" L1.SaveToFile("line.bin"); // 4. Read data from "line.bin" file and write it to L2 object L2.ReadFromFile("line.bin"); // 5. Display the value of L2 object L2.Print("L2 <= L1:"); }
Program result
L1 p1 => x = 2.5, y = 3.8 p2 => x = 4.1, y = 7.9 ----------------------- L2 p1 => x = 1, y = 1 p2 => x = 2, y = 2 ----------------------- L2 <= L1: p1 => x = 2.5, y = 3.8 p2 => x = 4.1, y = 7.9 -----------------------
⇑
Related topics
- C++ File System. General concepts. Examples. Open/close file
- Examples of using C++ for working with files
- Examples of working with text files. Modification of files. Sort data in files. Converting file lines to array. Replacing/deleting lines in a file. Inserting a line in the file
⇑