Функция шаблона класса для чтения входного потока - C ++ - PullRequest
0 голосов
/ 01 мая 2020

Я немного застрял в своем текущем проекте. Я создал метод в классе, который читает входные данные из файла и отправляет его в массив объектов Result (класс). Когда я это делаю, он использует метод потока ввода классов Result для чтения во входных данных так, как я хочу. Теперь у меня есть пользовательский шаблон класса Vector для динамических c массивов, где Result - мой вектор. Как мне нужно изменить мой синтаксис ввода и какой метод мне понадобится в Vector? Метод, который я использовал для чтения в массив объектов результатов, таков:

void Registration::SetSemester(unsigned semester1){
   semester = semester1;
}

void Registration::readFile(istream &input){
    long studentid1;
    unsigned semester1;

    input >> studentid1 >> semester1 >> count;

    SetStudentID(studentid1);
    SetSemester(semester1);

    for(unsigned i = 0; i < count; i++){
        input >> results[i];
    }
}

Это мой Vector.h:

#ifndef VECTOR_H
#define VECTOR_H
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

template <class T>
class Vector
{
    public:
        Vector(int size = 10);
        ~Vector();

        void initialize(unsigned from = 0);
        void expand();
        void add(const T &obj);
        int size() const{return this->nrofel;}

        T& operator[](const int index);
        const T& operator[](const int index) const;

    private:
        T **data;
        unsigned capacity;
        unsigned nrofel;
};

template <class T>
Vector<T>::Vector(int size){
    this->capacity = size;
    this->nrofel = 0;
    this->data = new T*[this->capacity];

    this->initialize();
}

template <class T>
T& Vector<T>::operator[](int index){
    if(index < 0 || index > this->nrofel){
        throw("Out of bounds");
    }
    return *this->data[index];
}

template <class T>
const T& Vector<T>::operator[](int index) const{
    if(index < 0 || index > this->nrofel){
        throw("Out of bounds");
    }
    return *this->data[index];
}

template <class T>
void Vector<T>::initialize(unsigned from){
    for(size_t i = from; i < this->capacity; i++){
        this->data[i] = nullptr;
    }
}

template <class T>
Vector<T>::~Vector(){
    for(size_t i = 0; i < capacity; i++){
        delete this->data[i];
    }
    delete[]this->data;
}

template <class T>
void Vector<T>::expand(){
    this->capacity *= 2;
    T** tempData = new T*[this->capacity];
    for(size_t i = 0; i < this->nrofel; i++){
        tempData[i] = new T(*this->data[i]);
    }

    for(size_t i = 0; i < this->nrofel; i++){
       delete this->data[i];
    }

    delete[] data;
    this->data = tempData;
    this->initialize(this->nrofel);
}

template <class T>
void Vector<T>::add(const T &obj){
    if(this->nrofel >= this->capacity){
        this->expand();
    }
    this->data[this->nrofel++] = new T(obj);
}

Мой метод add обрабатывает объекты и практически любое значение , но как сделать метод доступным для ввода из файла в массив?

1 Ответ

0 голосов
/ 01 мая 2020

Для этого вам нужно определить какой-либо тип сериализации для вашего векторного типа, а также вам нужно полагаться на содержащийся тип, чтобы знать, как сериализовать и десериализовать себя.

Сериализация и десериализация оба могут быть реализованы как операторы, и им даже не нужно быть друзьями вашего вектора, поскольку они могут работать с интерфейсом publi c.

Вот некоторый псевдокод, который вы можете использовать sh out:

template <typename T>
std::ostream & operator<<(std::ostream & stream, Vector<T> const & vec) {
    // Possibly write length information using vec.size()
    if (stream << vec.size()) {
        for (int i = 0; i < vec.size(); ++i) {
            // Possibly frame the data; regardless, write out each element using:
            if (!(stream << vec[i])) { break; }
        }
    }

    return stream;
}

template <typename T>
std::istream & operator>>(std::istream & stream, Vector<T> & vec) {
    // Possibly read length information...
    int size;
    if (stream >> size) {
        while (size--) {
            // Possibly read framing.
            T value;
            if (!(stream >> value)) { break; }
            vec.add(value);
        }
    }

    return stream;
}

Это, очевидно, не полная реализация. Вы, вероятно, захотите как-то кадрировать каждый элемент, чтобы вы знали, где каждый начинается и заканчивается.

T требуется реализация потоковых операторов для компиляции.


Сторона примечание: ваш шаблон Vector нарушает правило трех / пяти ; Вы определяете пользовательский деструктор, но не реализуете конструктор копирования, оператор копирования-назначения, конструктор перемещения или оператор назначения-перемещения. Если вы создаете копию значения Vector по значению, уничтожение источника или места назначения копии приведет к неопределенному поведению при использовании другого объекта.

Самое простое решение этой проблемы, предполагая, что C Компилятор ++ 11 предназначен для удаления этих членов, чтобы компилятор не генерировал неправильные версии:

template <class T>
class Vector
{
public:
    Vector(Vector const &) = delete;
    Vector(Vector &&) = delete;

    Vector & operator=(Vector const &) = delete;
    Vector & operator=(Vector &&) = delete;

    // ...
};

В более старых версиях C ++ объявляйте члены закрытыми, но не предоставляйте реализацию. Это предотвратит копирование извне класса или его друзей и вызовет ошибку времени соединения, если привилегированный код попытается сделать копию:

template <class T>
class Vector
{
private:
    // Don't implement any of these!
    Vector(Vector const &);
    Vector(Vector &&);

    Vector & operator=(Vector const &);
    Vector & operator=(Vector &&);

public:
    // ...
};

Конечно, если возможно, вы должны реализовать это так что ваш тип может быть правильно скопирован / перемещен.

...