Форум программистов, компьютерный форум CyberForum.ru

Собственный класс-итератор - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 73, средняя оценка - 4.92
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
01.10.2011, 20:51     Собственный класс-итератор #1
Создаю класс-итератор для класса Студенты.
Сам класс студенты:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#ifndef STUDENTS_H
#define STUDENTS_H
 
#include <string>
using std::string;
 
#include <iostream>
using std::cout;
using std::cerr;
 
#include <iomanip>
using std::setw;
 
#include <stdexcept>
using std::out_of_range;
 
class Students
{
    friend class StudentsIterator;
    struct ListItem
    {
        string fullname;
        string group;
        int year;
        int average;
        ListItem *Next;
        ListItem(string name="",int y=0,int aver=0,string gr="",ListItem* next=0)
        {
            fullname=name;
            group=gr;
            average=(aver>=0 && aver<=100 ? aver : -1);
            year=(y>=1950 && y<=2012 ? y : -1);
 
            if(average==-1 || year==-1)
             throw Exception("wrong data");
            Next=next;
        }
    };
 
    ListItem *Head;
    ListItem *Tail;
    ListItem *Current; //указатель на текущий элемент
    int count; // всего элементов
 
public:
    class Exception
    {
        string str;
        public:
        Exception(string data) :str(data){};
        string what(){return str;}
    };
 
    Students(): Head(0), Tail(0), Current(0), count(0) {}
 
    Students(string data, int y, int a, string g)
    {
        Head=Tail=new ListItem(data,y,a,g);
        Current=0;
        count=1;
    }
 
    ~Students(){this->deleteAll();}
 
 
    void addToTail(string data, int y, int a, string g);
    void addToHead(string data, int y, int a, string g);
 
 
    void deleteFromHead(bool mode=1);//1 - с предупреждением(исключением) если список пуст
    void deleteFromTail();
    void deleteAll();
 
    void print();
 
    //for iterators
    ListItem* begin(){return Head;}
    ListItem* end(){return Tail;}
};
Класс-итератор для класса студенты:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class StudentsIterator
{
    private:
    Students::ListItem* current;
 
    //функция для проверки что current инициализирован
    void correct(){if(current==0) throw Students::Exception("access denied");}
 
public:
 
    string first(){correct();return current->fullname;}
    string second(){correct();return current->group;}
    int third(){correct();return current->year;}
    int four(){correct();return current->average;}
 
    StudentsIterator() {current=0;}
 
    StudentsIterator(const Students &right)
    {
        *this=right;
    }
 
    StudentsIterator(Students::ListItem* right)
    {
        *this=right;
    }
 
 
    StudentsIterator* operator=(Students &right)
    {
        current=right.Current;
        return this;
    }
 
    //для указателей на элемент, например на начало или конец списка
    StudentsIterator* operator=(Students::ListItem* right)
    {
        current=right;
        return this;
    }
 
    Students::ListItem* operator++()
    {
        return (current=current->Next);
    }
 
    Students::ListItem* operator++(int)
    {
        Students::ListItem* temp=current;
        ++current;
        return temp;
    }
 
    Students::ListItem* operator*()
    {
        return current;
    }
 
};
 
#endif
Проблема заключается в перегрузке постфиксного оператора инкремента (operator++(int)) - почему-то при вызове из main я получаю вылет, компилятор предупреждений же никаких не выдаёт, но видать что-то же я сделал неправильно, но что именно? Почему я получаю вылет из программы (не моё исключение), может я как-то неправильно возвращаю указатель или ещё чего? Префиксный оператор ++ работает корректно.
Ну и если так есть какие комментарии по поводу улучшения реализации односвязного списка со студентами то тоже пишите.
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
01.10.2011, 21:27     Собственный класс-итератор #2
Gepar, Ну хоть разберитесь как итератор реализовывается... Операторы ++ должны возвращать объект итератора.

Пример итератора.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
template<class T>
class Iterator
{
public:
   Iterator(T* curr):current(curr)
   {
   }
   Iterator& operator =(const Iterator& other)
   {
       if (this != &other)
       {
           current = other.current;
       }
       return *this;
   }
   Iterator& operator ++()
   {
       ++current;
       return *this;
   }
   Iterator operator ++(int i)
   {
       Iterator tmp(current);
       ++current;
       return tmp;
   }
   T operator *()
   {
      return *current;
   }
   T* operator ->()
   {
      return current;
   }
private:
   T* current;
};
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
01.10.2011, 21:29  [ТС]     Собственный класс-итератор #3
И ещё вопрос по итераторам:
Как эта перегрузка оператора сравнения в итераторе
C++
1
2
3
4
    bool operator==(StudentsIterator& right) const
    {
        return (current==right.current);
    }
Может компилироваться, ведь current у меня находится в private части !Я уже было собрался написать функцию для возврата const ссылки на current,но внезапно оказалось что код скомпилировался, но как так ? Ведь right это ссылка на StudentsIterator с PRIVATE элементом current, как же это тогда компилятор даёт к нему доступ здесь, когда в main не даёт (что вполне логично) ?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
01.10.2011, 21:55     Собственный класс-итератор #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
А вот простенький код контейнера и итератора + совместимость с STL алгоритмами.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <iterator>
#include <iostream>
#include <algorithm>
#include <cstddef>
 
template<class T>
class Iterator;
 
template<class T>
class array
{
public:
   typedef Iterator<T> iterator;
   typedef size_t size_type;
   typedef T* pointer;
   typedef const T* const_pointer;
   typedef T& reference;
   typedef const T& const_reference;
   typedef T value_type;
   
   array():arr_(new T[0]), sz_(0)
   {
   }
   array(size_t sz):sz_(sz), arr_(new T[sz])
   {
      std::fill(arr_, arr_ + sz_, T());
   }
   array(const array& arr)
   {
      delete arr_;
      sz_ = arr.sz;
      arr_ = new T[sz_];
      std::copy(arr.arr_, arr.arr_ + sz_, arr_);
   }
   array& operator =(const array& arr)
   {
      array tmp(arr);
      swap(tmp);
      return *this;
   }
   ~array()
   {
      delete[] arr_;
   }
   Iterator<T> begin()
   {
      return Iterator<T>(arr_);
   }
   Iterator<T> end()
   {
      return Iterator<T>(arr_ + sz_);
   }
   T& operator [](size_t idx)
   {
      return arr_[idx];
   }
   const T& operator [](size_t idx) const
   {
      return arr_[idx];
   }
   size_t size() const
   {
      return sz_;
   }
private:
   void swap(array& first, array& second)
   {
      std::swap(first.arr_, second.arr_);
      std::swap(first.sz_, second.sz_);
   }
   T* arr_;
   size_t sz_;
};
 
template<class T>
class Iterator
{
public:
   typedef T value_type;
   typedef T* pointer;
   typedef T& reference;
   typedef std::forward_iterator_tag iterator_category;
   typedef ptrdiff_t difference_type;
   
   Iterator(T* curr):current(curr)
   {
   }
   Iterator& operator =(const Iterator& other)
   {
       if (this != &other)
       {
           current = other.current;
       }
       return *this;
   }
   Iterator& operator ++()
   {
       ++current;
       return *this;
   }
   Iterator operator ++(int i)
   {
       Iterator tmp(current);
       ++current;
       return tmp;
   }
   T& operator *()
   {
      return *current;
   }
   T* operator ->()
   {
      return current;
   }
   bool operator ==(const Iterator& other)
   {
      return current == other.current;
   }
   bool operator !=(const Iterator& other)
   {
      return !(*this == other);
   }
private:
   T* current;
};
 
int main()
{
   array<int> arr(5);
   for (array<int>::iterator iter = arr.begin(); iter != arr.end(); ++iter)
   {
      std::cout << *iter << std::endl;
   }
   for (array<int>::iterator iter = arr.begin(); iter != arr.end(); ++iter)
   {
      *iter = 5;
   }
   for (array<int>::iterator iter = arr.begin(); iter != arr.end(); ++iter)
   {
      std::cout << *iter << std::endl;
   }
   std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, "\n"));
}
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
01.10.2011, 23:21     Собственный класс-итератор #5
Цитата Сообщение от Gepar Посмотреть сообщение
Как эта перегрузка оператора сравнения в итераторе ... Может компилироваться
Потому что operator== - метод класса, объектом которого является right. Этот класс, разумеется, имеет доступ к своим приватным полям, и не важно, что operator== вызывается из одного объекта и принимает ссылку на другой, метод будет иметь доступ к обоим этим объектам. Ведь строка
C++
1
return (current==right.current);
эквивалентна
C++
1
return ((*this).current==right.current);
, и по вашей логике (*this).current тоже не должно работать (прямой доступ к закрытому члену).
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
02.10.2011, 02:10  [ТС]     Собственный класс-итератор #6
Цитата Сообщение от ForEveR Посмотреть сообщение
Gepar, Ну хоть разберитесь как итератор реализовывается... Операторы ++ должны возвращать объект итератора.
Исправил, спасибо, ещё немного доделаю и представлю на обозрение, буду благодарен если ещё раз покритикуете, ато эту лабу в отличии от тех заданий что я делал в последнее время, нужно будет сдавать.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.12.2011, 13:28     Собственный класс-итератор
Еще ссылки по теме:

Написать собственный класс для ввода и вывода строки, подсчета количества символов в строке C++
C++ Вывод двумерного массива используя собственный класс
Класс итератор для стека C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
metalion
Сообщений: n/a
16.12.2011, 13:28     Собственный класс-итератор #7
Новую тему решил не создавать, вопрос следующий:
Есть структура, созданная на основе паттерна компоновщик. Нужно обойти эту структуру итератором. Может кто привести готовое простенькое решение для понимая концепции?
Мои предположения:
3 вида итераторов(рекурсивный, пустой, обычный(к примеру для просмотра контейнера <vector>) ну и стек.+ необходим метод создания рекурсивных итераторов.
Yandex
Объявления
16.12.2011, 13:28     Собственный класс-итератор
Ответ Создать тему
Опции темы

Текущее время: 21:54. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru