In general, here is the task

Create a program that will write a container of integers to a file (text or binary) read whole numbers from a file (text or binary) to a container Writing a container to a file ( template method ) must contain the following sequence of operations opening a file writing numbers closing a file Reading method ( template method ) from the file should contain the sequence of the following operations: opening the file Reading the numbers and adding them to the container; closing the file; Use the Template method.

The problem here is that writing and reading are 2 different types ( ofstream and fstream ). And if you make one method in the interface, then you will not be able to choose ofstream or ifstream during inheritance, and if you make different methods, then you will get rid of this pattern. Here is the code:

  class Base { virtual void open(ofstream &a) = 0; virtual void doing(array<int, 6>::iterator it, ofstream &a) = 0; void close(ofstream &a) { a.close(); } public: void execute( array<int, 6>::iterator it, ofstream &a) { open(a); doing(it,a); close(a); } }; class Writer:public Base { virtual void open(ofstream &a) { a.open("FIle.bin", ios::binary); if (!a) cout << "Error\n"; } virtual void doing( array<int, 6>::iterator it, ofstream &a) { a.write((char*)&it, sizeof(it)); } }; class Reader:public Base { virtual void open(ofstream &a) { a.open("FIle.bin", ios::binary); if (!a) cout << "Error\n"; } virtual void doing(array<int, 6>::iterator it, ofstream &a) { a.read((char*)&it, sizeof(it)); } }; void main() { array<int, 6> ll {0,1,2,3,4,5}; Base *arr[]{ &Writer(),&Reader() }; ofstream f1; ifstream f2; arr[1]->execute(ll.begin(),f2); arr[0]->execute(ll.begin(), f1); for (int i = 0; i < 6; i++) cout << ll[i]<<" "; cout << "\n\n"; } 
  • Edit your code with errors and add it here, then the probability of an answer to your question will increase. - Fess Laeda
  • @IlonMask updated - Hadler2
  • use std :: fstream references instead of std :: ofstream references as function arguments. In the second line of the main function, you have a pair of dangling pointers. - acade
  • @acade What do the dangling pointers mean? - Hadler2
  • @ Hadler2, you take the address of a temporary object. &Writer() - the object is created, its address is remembered, and the object is destroyed, and the address taken (pointer in the arr array) will point to an object that no longer exists. - acade

1 answer 1

Since the implementation of the doing method can perform both writing and reading, passing a reference to std::ofstream not suitable. The standard library provides the std::fstream class, which is a merge of std::ifstream and std::ofstream , what you need.

Further, the semantics of the doing methods (from Writer -a):

 a.write((char*)&it, sizeof(it)); 

This code does not do what you expect. You take the iterator address it , which has nothing to do with the data pointed to by the iterator. It is necessary to record not the address of the iterator, but the data it stores.

The iterator is fine, but you need to work with the sequence. An iterator must be passed to the beginning and end of the sequence.

Because std::fstream works with both input streams and output streams; you need to explicitly specify for what purpose the stream opens: for input ( std::ios::in ) or for output ( std::ios::out ).


 Base *arr[]{ &Writer(),&Reader() }; 

In this segment of the code: an object of type Writer (everything said also applies to the Reader ). The operation of taking the address is performed, the address is written to the arr array, and then the object whose address we memorized is destroyed. As a result, we get a hanging pointer.

One of the possible correct options:

 Writer writer{}; Reader reader{}; Base* arr[] = { &writer, &reader }; 

Correct implementation:

Base class

 class Base { virtual void open(std::fstream &a) = 0; virtual void doing(array<int, 6>::iterator first, // итератор на начало array<int, 6>::iterator last, // итератор на конец std::fstream& stream // ссылка на поток ) = 0; void close(std::fstream &a) { a.close(); } public: // те же изменения void execute(array<int, 6>::iterator first, array<int, 6>::iterator last, std::fstream &a) { open(a); doing(first, last, a); close(a); } }; 

Writer class

 class Writer : public Base { virtual void open(std::fstream &a) override { a.open("FIle.bin", ios::binary | std::ios::out); if (!a) cout << "Error\n"; } virtual void doing(array<int, 6>::iterator first, array<int, 6>::iterator last, std::fstream& stream) override { // проверка на доступность потока // проверка на валидность итераторов for (; first != last; ++first) { // получаем указатель на реальные данные которые хранит итератор const char* pointer_to_data = reinterpret_cast<const char*>(&*first); // записываем эти данные // sizeof(int), sizeof(*first), // sizeof(std::array<int, 6>::value_type) : как угодно stream.write(pointer_to_data, sizeof(*first)); } } }; 

Reader class

 class Reader : public Base { virtual void open(std::fstream &a) override { a.open("FIle.bin", ios::binary | ios::in); if (!a) cout << "Error\n"; } virtual void doing(array<int, 6>::iterator first, array<int, 6>::iterator last, std::fstream& stream) override { // проверка на доступность потока // проверка на валидность итераторов for (; first != last; ++first) { // проверка активен ли поток и может ли быть произведено чтение // получаем указатель на место памяти, куда указывает итератор char* pointer_to_data = reinterpret_cast<char*>(&*first); stream.read(pointer_to_data, sizeof(*first)); } } }; 

Also, in your example, you first perform a read operation, and then a write operation. Check for one entry can work as follows:

 int main() { Reader reader{}; Writer writer{}; std::fstream stream{}; // кстати, достаточно одного потока fstream std::array<int, 6> arr1{ 1, 2, 3, 4, 5, 6 }; std::array<int, 6> arr2; std::cout << "arr1 до записи, (arr2 пустой): \n"; for (size_t i = 0; i < 6; ++i) std::cout << arr1[i] << "\t"; std::cout << "\n"; // записываем данные из arr1 writer.execute(arr1.begin(), arr1.end(), stream); // читаем данные в arr2 reader.execute(arr2.begin(), arr2.end(), stream); std::cout << "arr2 после чтения: \n"; for (size_t i = 0; i < 6; ++i) std::cout << arr2[i] << "\t"; std::cout << "\n"; return 0; } 

It is worth noting that this solution is very inflexible. In an amicable way, it is first necessary to record the number of elements in the file. But since The solution is (apparently) used for educational purposes, these points can be neglected.