Форум программистов, компьютерный форум, киберфорум С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/21: Рейтинг темы: голосов - 21, средняя оценка - 4.52
2 / 2 / 0
Регистрация: 26.12.2012
Сообщений: 17

Друзья шаблонного класса. Использование вложенной в класс структуры

03.01.2015, 18:32. Показов 4406. Ответов 10
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет!

Изучаю книгу "Прата С. - Язык программирования С++. Лекции и упражнения". Разобрал тему шаблоны классов и в заданиях для тренировки было предложено переделать класс очереди в шаблонный класс. Очередь реализована при помощи связанного списка (точнее односвязного). Для его работы в классе присутствует вложенное определение структуры Node, которая содержит информационную часть (сами данные), а также указатель на следующий узел. Чтобы правильно обработать связный список, в классе определены данные-члены *front и *rear типа Node. Это адрес первого и последнего узла.

По заданию в качестве типа, который будет передан шаблону выступает другой сложный класс, его определение я не стал приводить.

Проблема возникла, когда я попытался написать дружественную для класса функцию вывода всего содержимого списка на экран. Для этого я хочу "перебрать" с помощью цикла все узлы - от *front до *rear. Но при попытке создать в теле дружественной функции переменную i типа Node, которая иницилизирована нулевым значением, MVS выдает ошибку:
Ошибка 1 error C2274: приведение типов в стиле функции: недопустимо в качестве выражения с правой стороны оператора "." (строка 143 заголовочного файла)

Заголовочный файл:
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
144
145
146
147
148
149
// H_task_3.h -- класс очереди из объектов Worker
#ifndef H_TASK_3_H_
#define H_TASK_3_H_
 
#include <iostream>  // Добавление модуля ввода/вывода информации (C++)
#include <string>    // Добавление заголовочного файла для доступа к классу string
using namespace std;
 
// Прототип шаблонной дружественной функции:
template <class T>
ostream & PrintQueue(ostream &os, const T &); 
 
//...
// Определение классов Worker, Waiter, Singer и SingingWaiter
//...
 
// Класс очереди
template <class T>
class QueueTP
{
private:
    // Область действия класса
    // Node - это ВЛОЖЕННОЕ определение структуры, локальное для данного класса:
    struct Node { T item; struct Node *next; };
    enum {Q_SIZE=10}; // Константа в виде перечисления
    // Закрытые члены класса для организации ОДНОСВЯЗНОГО СПИСКА:
    Node *front; // Указатель на начало списка
    Node *rear;  // Указатель на конец списка
    int items;   // Текущее количество элементов в списке
    // Максимальное количество элементов в списке:
    const int qsize;
    //Запрещаем для класса использовать явные конструкторы копирования и операции присваивания:
    QueueTP(const QueueTP & q) : qsize(0) { }
    QueueTP & operator=(const QueueTP & q) { return *this;}
public:
    QueueTP(int qs=Q_SIZE); // Конструктор + конструктор по умолчанию: создает очередь с предельным размером qs
    ~QueueTP();             // Деструктор
    bool isempty() const; // Проверка, является ли очередь пустой
    bool isfull() const;  // Проверка, является ли очередь заполненной
    int queuecount() const; // Возвращает текущее количество элементов в очереди
    bool enqueue(const T &item); // Добавляет элемент в конец очереди
    bool dequeue(T &item);       // Удаляет элемент из начала очереди
    friend ostream & PrintQueue< QueueTP<T> >(ostream &os, const QueueTP<T> &); // Вывод всех данных, хранящихся в списке
};
 
 
// Конструктор + конструктор по умолчанию: создает пустую очередь с предельным размером qs
template <class T>
QueueTP<T>::QueueTP(int qs) : qsize(qs)
{
    // По умолчанию очередь может содержать до десяти элементов, но это ограничение может быть изменено с помощью аргумента при явной инициализации.
    front=rear=NULL; // или nullptr
    items=0;
}
 
// Деструктор
template <class T>
QueueTP<T>::~QueueTP()
{
    Node *temp;
    while (front!=NULL) // Пока очередь не пуста:
    {
        temp=front;  // Сохраняем адресс начального элемента (узла)
        front=front->next; // Переустанавливаем указатель front на следующий элемент
        delete temp; // Удаляем предыдущий начальный элемент
    }
}
 
// Проверка, является ли очередь пустой
template <class T>
bool QueueTP<T>::isempty() const
{
    return items==0;
}
 
// Проверка, является ли очередь заполненной
template <class T>
bool QueueTP<T>::isfull() const
{
    return items==qsize;
}
 
// Возвращает текущее количество элементов в очереди
template <class T>
int QueueTP<T>::queuecount() const
{
    return items;
}
 
// Добавляет элемент в конец очереди
template <class T>
bool QueueTP<T>::enqueue(const T &item)
{
    // Если очередь уже полна, завершаем программу. В приведенной реализации максимальный размер задается пользователем через конструктор.
    if (isfull())
        return false;
    // Создаем новый узел. Если new не может создать его, генерируется исключение std::bad_alloc (см. главу 15). Если не написан код для обработки этого исключения, программа завершается.
    Node *add=new Node;
    // Помещаем соответствующие значения в узел: копируем данные, которые содержал объект типа Item, переданный в метод, в часть данных узла. Затем заносим в указатель следующего узла значение NULL (либо 0, либо nullptr в С++11). Это подготовка к тому, что узел будет последним элементом в очереди.
    add->item=item; // Не забывай, что в качестве компонента (узла) выступает структура Node.
    add->next=NULL;
    // Увеличиваем счетчик элементов (items) на единицу:
    items++;
    // Присоединяем созданный узел в конец очереди:
    // Тут есть 2 варианта:
    if (front==NULL) // Если очередь пуста...
        front=add;   //...помещаем новый элемент в начало списка - присваиваем указателю front ссылку на новый узел. Т.е. если в очереди всего один узел, то он является и начальным (front), и конечным (rear). Конечный мы устанавливаем ниже (rear=add;) в любом случае.
    else // В противном случае помещаем новый элемент в конец списка: ...
        rear->next=add; //...для этого в указатель next предыдущего конечного узла заносится ссылка на новый конечный узел.
    rear=add; // Устанавливаем указатель конца (rear) на новый последний узел
    return true;
}
 
// Удаляет элемент из начала очереди
template <class T>
bool QueueTP<T>::dequeue(T &item)
{
    // Если очередь уже пуста, завершаем программу:
    if(front==NULL)
        return false;
    // Копируем элемент из начального узла в ссылочную переменную item, переданную в метод:
    item=front->item; // 1-ая составляющая
    // Уменьшаем счетчик элементов (items) на единицу:
    items--;
    // Сохраняем расположение (адрес) начального узла для последующего удаления:
    Node *temp=front;
    // Это необходим потому, что на следующем шаге очищается память, в которой находился предыдущий начальный узел. 
    // Удаляем начальный узел из очереди. Для этого в указатель-член front объекта QueueTP заносим указатель на следующий узел, адрес которого находится в front->next. Другими словами переустанавливаем указатель front на следующий элемент:
    front=front->next; // 2-ая составляющая
    // Удаляем предыдущий начальный узел для его повторного использования в дальнейшем:
    delete temp;
    // Если список теперь пуст, то занести в rear значение NULL. (Начальный указатель уже равен NULL после установки front->next.) Как всегда, вместо NULL можно занести значение 0 или (в С++11) nullptr.
    if (items==0)
        rear=NULL;
    return true;
}
 
// Вывод всех данных, хранящихся в списке
template <class T> 
ostream & PrintQueue(std::ostream &os, const T &q) // Работает
{
    os<<q.items<<endl;
    q.Node *i=nullptr; // ОШИБКА!!!
    for (i=q.front; i!=NULL; i=i->next)
    {
        // Вывод данных конкретного узла на экран
    }
    return os;
}
Основной код программы:
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
#include <locale>
#include "H_task_3.h"
 
int main()
{
    setlocale(LC_ALL,"Russian"); // Строчка для Русского языка
    
    cout<<"Введите максимальный размер очереди: ";
    int qs;
    cin>>qs;
    // По заданию в качестве типа, который будет передан шаблону выступает указатель на другой сложный класс, его определение я не стал приводить:
    QueueTP<Worker *> lolas(qs); // Очередь может содержать до qs людей
    
    // Временный объект для хранения данных нового работника:
    Worker *temp;
    
    int ct;
    for (ct=0; ct<qs; ct++)
    {
        char choice;
        cout<<"Enter the employee category:\n"
        <<"w: waiter  s: singer  "
        <<"t: singing waiter  q: quit\n";
        cin>>choice;
        while (strchr("wstq", choice)==NULL) // Возвращает адрес первого вхождения символа choice в строку "wstq" (если символ не найден, возвращается указатель NULL).
        {
            cout<<"Please enter a w, s, t, or q: ";
            cin>>choice;
        }
        if (choice=='q')
            break;
        // Выделение памяти для выбранного объекта класса. Это пример полиморфизма: здесь присваиваются адреса различных видов классов указателям на базовые классы:
        switch(choice)
        {
        case 'w':
            temp=new Waiter;
            break;
        case 's':
            temp=new Singer;
            break;
        case 't':
            temp=new SingingWaiter;
            break;
        }
        cin.get();
        // Ввод данных в созданный объект:
        temp->Set();
        // Добавляем нового клиента в конец очереди, при это создается новый узел. На этом шаге как раз и осуществляется копирование данных, которые содержит временный объект, в часть данных нового узла:
        lolas.enqueue(temp);
    }
    cout<<endl;
    // Вывод всех данных, хранящихся в списке:
    PrintQueue(cout, lolas); // <<-- ПРОБЛЕМА В ЭТОЙ ФУНКЦИИ
    
    //...
    //...
    //...
    
    system("pause");
    return 0;
}
Подскажите как решить проблему. Заранее благодарен
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
03.01.2015, 18:32
Ответы с готовыми решениями:

Как корректно передать в метод шаблонного класса объект шаблонного класса в качестве параметра?
header.h template &lt;class T&gt; class MyVector { public: void swap(MyVector&lt;T&gt;Vector); } template &lt;class T&gt; void...

Создать экземпляр структуры шаблонного класс
Добрый день. У меня возникла проблема при создании шаблонного класса с структурой. Вот код, проблема в 37 строке: using namespace std; ...

Использование фабрики для шаблонного класса
Вот класс template &lt;class T&gt; class ConcreteConverter { T _value; long long _maxValue; long long _minValue; public: ...

10
Эксперт С++
 Аватар для hoggy
8972 / 4318 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.01.2015, 18:37
Лучший ответ Сообщение было отмечено DESergik как решение

Решение

Объясните по-русски, что именно вы пытаетесь сделать в этой строке:

C++ Скопировано
1
q.Node *i=nullptr; // ОШИБКА!!!
Что по вашему должно происходить в этой строке?


Может быть вы имели ввиду:

C++ Скопировано
1
typename T::Node* i=nullptr;
?

То есть, вы хотели создать указатель на объект вложенной структуры?



Лекарство:

C++ Скопировано
1
2
3
4
5
6
7
8
9
10
11
// Вывод всех данных, хранящихся в списке
template <class T> 
ostream & PrintQueue(std::ostream &os, const T &q) // Работает
{
    os<<q.items<<endl;
    for ( auto i=q.front; i!=nullptr; i=i->next)
    {
        // Вывод данных конкретного узла на экран
    }
    return os;
}
1
2 / 2 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 22:44  [ТС]
hoggy, в этой строчке я пытаюсь создать нулевой указатель на структуру типа Node для его использования в цикле for ниже. При помощи цикла for затем я пытаюсь "перебрать" все узлы - от *front до *rear и вывести данные, которые они содержат (член item структуры Node).

Добавлено через 43 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
То есть, вы хотели создать указатель на объект вложенной структуры?
Да, именно это и хотел сделать. Большое спасибо за помощь

Добавлено через 3 часа 10 минут
Автоматическое выведение типа это удобно конечно, но всё таки очень хочется узнать, как вручную правильно объявить тип для переменной i. Как ни пытался, не смог этого сделать. Поэтому вопрос ещё открыт.
0
Эксперт С++
 Аватар для hoggy
8972 / 4318 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.01.2015, 22:49
Цитата Сообщение от DESergik Посмотреть сообщение
как вручную правильно объявить тип для переменной i. Как ни пытался, не смог этого сделать. Поэтому вопрос ещё открыт.
Это я для кого оставил?

Цитата Сообщение от hoggy Посмотреть сообщение
typename T::Node* i=nullptr;
1
2 / 2 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 23:02  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
Это я для кого оставил?
Сообщение от hoggy
typename T::Node* i=nullptr;
hoggy, понял, извиняюсь за свою невнимательность.
Только запись данной строчки мне не очень понятна... Ведь вложенная структура Node - это член класса QueueTP, почему данный член нельзя использовать, например с таким синтаксисом:
C++ Скопировано
1
q.Node *i=nullptr; // Не работает
Не понимаю этот момент
0
Эксперт С++
 Аватар для hoggy
8972 / 4318 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.01.2015, 23:14
Цитата Сообщение от DESergik Посмотреть сообщение
Ведь вложенная структура Node - это член класса QueueTP, почему данный член нельзя использовать, например с таким синтаксисом:
Во-первых, вложенная структура не является членом класса.
Она является самой обычной структурой, просто объявлена в пространстве имени класса-хозяина. Вот и все.

С точно таким же успехом вы могли бы объявить структуру и снаружи класса.

Во-вторых, у вас нет функции.
У вас есть шаблон функции:

Цитата Сообщение от DESergik Посмотреть сообщение
template <class T>
ostream & PrintQueue(ostream &os, const T &);
Это шаблон. В который вместо T можно подсунуть все что угодно.

И когда компилятор будет его парсить, он ещё не будет знать что именно вы туда подсунете.
Ни о каких QueueTP в шаблоне даже намека нет.

В-третьих - правила языка.

Вложенная структура класса - есть собственность этого класса.
Собственность класса, а не отдельного его экземпляра.

Понимаете?

Хотите обратиться к структуре которая принадлежит классу - так и обращайтесь к самому классу.
1
2 / 2 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 23:51  [ТС]
hoggy, спасибо за ответ. Кажется понял. Попробую написать свои мысли.
Согласно теории, приведенной в учебнике, чтобы каждая специализация класса получала соответствующую специализацию друга мы используем связанные шаблонные друзья. Для этого, перед объявлением всех классов определяется специальный прототип шаблонной дружественной функции:
C++ Скопировано
1
2
template <class T>
ostream & PrintQueue(ostream &os, const T &);
Вторым шагом, мы определяем этого друга в методах класса, но уже так:
C++ Скопировано
1
friend ostream & PrintQueue< QueueTP<T> >(ostream &os, const QueueTP<T> &);
Т.е. неизвестный тип T & в прототипе шаблона заменяется на QueueTP<T> & - имя класса. Теперь наша функция PrintQueue является другом для шаблонного класса QueueTP<T>. И т.к.
Цитата Сообщение от hoggy Посмотреть сообщение
Вложенная структура класса - есть собственность этого класса.
Собственность класса, а не отдельного его экземпляра.
Цитата Сообщение от hoggy Посмотреть сообщение
Хотите обратится к структуре которая принадлежит классу, обращайтесь к классу.
то мы и применяем данный синтаксис для доступа к вложенной структуре класса, ведь здесь T - это по сути имя класса:
C++ Скопировано
1
typename T::Node* i=nullptr;
Правильно понял?
0
Эксперт С++
 Аватар для hoggy
8972 / 4318 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.01.2015, 00:12
Цитата Сообщение от DESergik Посмотреть сообщение
Правильно понял?
Да. Все верно.

Единственное: я объявляю шаблон дружественной функции немножко иначе:

http://rextester.com/WGBIOJ23957

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
#include <iostream>
 
 
template<class T> class example
{
    struct Node{ T value; };
    
    Node mValue;
    
public:
    example()
        : mValue( {10} )
    {}
    
    template<class U>friend ::std::basic_ostream<U>& 
        operator<<( ::std::basic_ostream<U>& os, const example& obj )
        {
            return os << obj.mValue.value;
        }
    
};
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    example<int> ex;
    
    std::cout << "example: "<< ex << '\n';
}

Обратите внимание на синтаксис объявления шаблона дружественной функции:

C++ Скопировано
1
2
3
4
5
template<class U>friend ::std::basic_ostream<U>& 
        operator<<( ::std::basic_ostream<U>& os, const example& obj )
        {
            return os << obj.mValue.value;
        }
1. Шаблон оперирует типом: ::std::basic_ostream<U>
Можно было бы вообще избавиться от шаблоной-версии, и сделать френдом обычную, не шаблонную функцию.

Однако данный вариант позволяет вообще не включать хэдэр iostream, если вы не планируете им пользоваться.

Здесь используется фундаментальное свойство шаблонов:
"если шаблон не инстанцировать, то код шаблона не войдет в компиляцию".

Кроме того, такой прототип позволяет работать не только с cout, но и с wcout, и вообще с любыми инстансами шаблона ::std::basic_ostream

2.
Обратите внимание на const example& obj
Такая форма записи позволяет избежать необходимости писать угловые скобочки, что делает синтаксис проще.

3. Шаблон дружественной функции объявлен и определен прямо в теле класса.
Это не значит, что функция стала методом класса.

Вовсе нет, она по прежнему свободная отдельная от класса функция.
Однако благодаря тому, что её не обязательно выносить за пределы декларации класса, можно ещё упростить синтаксис, и уменьшить количество шаблоно-кода.
1
2 / 2 / 0
Регистрация: 26.12.2012
Сообщений: 17
04.01.2015, 12:19  [ТС]
hoggy, большое спасибо за объяснение. Теперь разобрался
0
4 / 4 / 0
Регистрация: 08.02.2014
Сообщений: 57
14.07.2015, 15:13
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
//template_class.h
 
#ifndef TEMPLATE_CLASS_H_
#define TEMPLATE_CLASS_H_
 
 
#include <string>
#include <iostream> 
#include <cstdlib>
 
using namespace std;
 
//Очередь, содержащая элементы Worker
 
class Worker
{
private:
    std::string fullname;
    long id;
protected:
    virtual void Data() const;
    virtual void Get();
public:
    Worker() :fullname("no one"), id(0L){ ; };
    Worker(const std::string & s, long n) :fullname(s), id(n){ ; };
    virtual ~Worker() = 0;
    virtual void Set() = 0;
    virtual void Show() const = 0;
};
 
class Waiter : virtual public Worker
{
private:
    int panache;
protected:
    void Data() const;
    void Get();
public:
    Waiter() :Worker(), panache(0) {};
    Waiter(const std::string & s, long n, int p = 0);
    Waiter(const Worker & wk, int p = 0) :Worker(wk), panache(0) {};
    void Set();
    void Show() const;
};
 
class Singer : virtual public Worker
{
protected:
    enum{ other, alto, contralto, soprano, bass, baritone, tenor };
    enum{ Vtypes = 7 };
    void Data() const;
    void Get();
private:
    static char *pv[Vtypes];
    int voice;
public:
    Singer() : Worker(), voice(other) {};
    Singer(const std::string & s, long n, int v = other) : Worker(s, n), voice(v) {};
    Singer(const Worker & wk, int v = other) : Worker(wk), voice(v) {};
    void Set();
    void Show() const;
};
 
//Множественное наследование
class SingingWaiter : public Singer, public Waiter
{
protected:
    void Data() const;
    void Get();
public:
    SingingWaiter() {};
    SingingWaiter(const std::string & s, long n, int p = 0, int v = other) : Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
    SingingWaiter(const Worker & wk, int p = 0, int v = other) : Worker(wk), Waiter(wk, p), Singer(wk, v) {}
    SingingWaiter(const Waiter & wt, int v = other) : Worker(wt), Waiter(wt), Singer(wt, v) {}
    SingingWaiter(const Singer & wt, int p = 0) : Worker(wt), Waiter(wt, p), Singer(wt) {}
    void Set();
    void Show() const;
};
 
template<class T>
 
class QueueTP
{
private:
    //Node - вложенная структура
    struct Node
    {
        T item;
        struct Node * next;
    };
    enum { Q_SIZE = 10 };
 
    //Закрытые члены класса
    Node * front;
    Node * rear;
    int items;
    const int qsize;
 
    //Упреждающее объявление для предотвращения открытого копирования
    QueueTP(const QueueTP & q) : qsize(0){};
    QueueTP & operator=(const QueueTP & q){ return *this; };
public:
    QueueTP(int qs = Q_SIZE);
    ~QueueTP();
    bool isempty() const;
    bool isfull() const;
    int queuecount() const;
    bool enqueue(const T & item);
    bool dequeue(T & item);
    friend std::ostream & PrintQueue(std::ostream & os, const QueueTP<T> &);
};
 
//Методы Queue
template<class T>
QueueTP<T>::QueueTP(int qs) : qsize(qs)
{
    front = rear = nullptr;
    items = 0;
};
 
template<class T>
QueueTP<T>::~QueueTP()
{
    Node * temp;
    while (front != NULL)
    {
        temp = front;
        front = front->next;
        delete temp;
    };
};
 
template<class T>
bool QueueTP<T>::isempty() const
{
    return items == 0;
};
 
template<class T>
bool QueueTP<T>::isfull() const
{
    return items == qsize;
};
 
template<class T>
int QueueTP<T>::queuecount() const
{
    return items;
};
 
template<class T>
std::ostream & PrintQueue(std::ostream & os, const T & q)
{
    os << q.items << endl;
    typename T::Node* i = nullptr;
    for (i = q.front; i != NULL; i = i->next)
    {
        os << q->item.Show() << endl;
    }
    return os;
}
 
//Добавление элемента в очередь
template<class T>
bool QueueTP<T>::enqueue(const T & item)
{
    if (isfull())
    {
        return false;
    };
 
    Node * add = new Node;                                                                  //создание узла
 
    //При неудачном выполнении операция new генерирует исключение std::bad_alloc
    add->item = item;
    add->next = NULL;
    items++;
    if (front == NULL)
    {
        front = add;
    }
    else
    {
        rear->next = add;
    }
    rear = add;
    return true;
};
 
//Помещение элемента frint в переменную item и его удаление из очереди
template<class T>
bool QueueTP<T>::dequeue(T & item)
{
    if (front == NULL)
    {
        return false;
    };
    item = front->item;
    items--;
    Node * temp = front;
    front = front->next;
    delete temp;
    if (items == 0)
    {
        rear = NULL;
    };
    return true;
};
 
 
 
//Методы Worker
 
Worker::~Worker(){ ; }
 
//Защищённые методы
 
void Worker::Data() const
{
    cout << "Name: " << fullname << endl;
    cout << "Employee ID: " << id << endl;
}
 
void Worker::Get()
{
    getline(cin, fullname);
    cout << "Enter worker`s ID: ";
    cin >> id;
    while (cin.get() != '\n')
    {
        continue;
    }
}
 
//Методы Waiter
void Waiter::Set()
{
    cout << "Enter waitor`s name: ";
    Worker::Get();
    Get();
}
 
void Waiter::Show() const
{
    cout << "Category: waiter\n";
    Worker::Data();
    Data();
}
 
//Защищённые методы
void Waiter::Data() const
{
    cout << "Panache rating: " << panache << endl;
}
 
void Waiter::Get()
{
    cout << "Enter waiter`s panache rating: ";                                              //Ввод индекса элегантности официанта
    cin >> panache;
    while (cin.get() != '\n')
        continue;
}
 
//Методы Singer
char * Singer::pv[Singer::Vtypes] = { "other", "alto", "contralto",
"soprano", "bass", "baritone", "tenor" };
void Singer::Set()
{
    cout << "Enter singer`s name: ";
    Worker::Get();
    Get();
}
 
void Singer::Show() const
{
    cout << "Category: singer\n";
    Worker::Data();
    Data();
}
 
//Защищённые методы
void Singer::Data() const
{
    cout << "Vocal range: " << pv[voice] << endl;
}
 
void Singer::Get()
{
    cout << "Enter number for singer`s vocal range:\n";
    int i;
    for (i = 0; i < Vtypes; i++)
    {
        cout << i << ": " << pv[i] << " ";
        if (i % 4 == 3)
            cout << endl;
    }
    if (i % 4 == 0)
        cout << '\n';
    cin >> voice;
    while (cin.get() != '\n')
        continue;
}
 
//Методы SingerWaiter
void SingingWaiter::Data() const
{
    Singer::Data();
    Waiter::Data();
}
 
void SingingWaiter::Get()
{
    Waiter::Get();
    Singer::Get();
}
 
void SingingWaiter::Set()
{
    cout << "Enter singing waiter`s name: ";
    Worker::Get();
    Get();
}
 
void SingingWaiter::Show() const
{
    cout << "Category: singing waiter\n";
    Worker::Data();
    Data();
};
 
 
#endif // !TEMPLATE_CLASS_H_
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
//usemain.cpp
 
#include <iostream>
#include "template_class.h"
#include <cstring>
#include <Windows.h>
 
int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::strchr;
 
    int qs,counts;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    cout << "Ввод размера очереди: ";
    cin >> qs;
 
    //Временный объект
    Worker *temp;
    QueueTP<Worker *> ochered(qs);
 
    for ( counts = 0; counts < qs; counts++)
    {
        char choice;
        cout << "Enter the employee category:\n"
             << "w: waiter s: singer "
                << "t: singing waiter q: quit\n";
            cin >> choice;
            while (strchr("wstq", choice) == NULL)
            {
                cout << "Please enter a w, s, t, or q: ";
                cin >> choice;
            }
            if (choice == 'q')
                break;
            switch (choice)
            {
            case 'w':
                temp = new Waiter;
                break;
            case 's':
                temp = new Singer;
                break;
            case 't':
                temp = new SingingWaiter;
                break;
            }
            cin.get();
            // Ввод данных в созданный объект:
            temp->Set();
            // Добавляем нового клиента в конец очереди, при это создается новый узел. На этом шаге как раз и осуществляется копирование данных, которые содержит временный объект, в часть данных нового узла:
            ochered.enqueue(temp);
    }//End for
 
    int ct;
    for (ct = 0; ct < counts; ct++)
    {
        cout << "Template not works" << endl;
    }
    
    PrintQueue(cout, ochered);
 
    cout << "Bye.\n";
    system("pause");
    return EXIT_SUCCESS;
}
Вроде всё правильно а компилироватся отказывается, класс воркер и прочее брал из других своих заданий а остальное отсюда, компилю в vsu 2013 4upd.
0
4 / 4 / 0
Регистрация: 08.02.2014
Сообщений: 57
16.07.2015, 15:50
Так ни кто и не помог но я сделал правда данные из очереди выводятся на экран после удаления из очереди.
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
//template_class.h
 
#ifndef TEMPLATE_CLASS_H_
#define TEMPLATE_CLASS_H_
 
 
#include <string>
#include <iostream> 
#include <cstdlib>
 
using namespace std;
 
//Очередь, содержащая элементы Worker
 
class Worker
{
private:
    std::string fullname;
    long id;
protected:
    virtual void Data() const;
    virtual void Get();
public:
    Worker() :fullname("no one"), id(0L){ ; };
    Worker(const std::string & s, long n) :fullname(s), id(n){ ; };
    virtual ~Worker() = 0;
    virtual void Set() = 0;
    virtual void Show() const = 0;
};
 
class Waiter : virtual public Worker
{
private:
    int panache;
protected:
    void Data() const;
    void Get();
public:
    Waiter() :Worker(), panache(0) {};
    Waiter(const std::string & s, long n, int p = 0);
    Waiter(const Worker & wk, int p = 0) :Worker(wk), panache(0) {};
    void Set();
    void Show() const;
};
 
class Singer : virtual public Worker
{
protected:
    enum{ other, alto, contralto, soprano, bass, baritone, tenor };
    enum{ Vtypes = 7 };
    void Data() const;
    void Get();
private:
    static char *pv[Vtypes];
    int voice;
public:
    Singer() : Worker(), voice(other) {};
    Singer(const std::string & s, long n, int v = other) : Worker(s, n), voice(v) {};
    Singer(const Worker & wk, int v = other) : Worker(wk), voice(v) {};
    void Set();
    void Show() const;
};
 
//Множественное наследование
class SingingWaiter : public Singer, public Waiter
{
protected:
    void Data() const;
    void Get();
public:
    SingingWaiter() {};
    SingingWaiter(const std::string & s, long n, int p = 0, int v = other) : Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
    SingingWaiter(const Worker & wk, int p = 0, int v = other) : Worker(wk), Waiter(wk, p), Singer(wk, v) {}
    SingingWaiter(const Waiter & wt, int v = other) : Worker(wt), Waiter(wt), Singer(wt, v) {}
    SingingWaiter(const Singer & wt, int p = 0) : Worker(wt), Waiter(wt, p), Singer(wt) {}
    void Set();
    void Show() const;
};
 
 
template<class T>
 
class QueueTP
{
private:
    //Node - вложенная структура
    struct Node
    {
        T item;
        struct Node * next;
    };
    enum { Q_SIZE = 10 };
 
    //Закрытые члены класса
    Node * front;
    Node * rear;
    int items;
    const int qsize;
 
    //Упреждающее объявление для предотвращения открытого копирования
    QueueTP(const QueueTP & q) : qsize(0){};
    QueueTP & operator=(const QueueTP & q){ return *this; };
public:
    QueueTP(int qs = Q_SIZE);
    ~QueueTP();
    bool isempty() const;
    bool isfull() const;
    int queuecount() const;
    bool enqueue(const T & item);
    bool dequeue(T & item);
};
 
//Методы Queue
template<class T>
QueueTP<T>::QueueTP(int qs) : qsize(qs)
{
    front = rear = nullptr;
    items = 0;
};
 
template<class T>
QueueTP<T>::~QueueTP()
{
    Node * temp;
    while (front != NULL)
    {
        temp = front;
        front = front->next;
        delete temp;
    };
};
 
template<class T>
bool QueueTP<T>::isempty() const
{
    return items == 0;
};
 
template<class T>
bool QueueTP<T>::isfull() const
{
    return items == qsize;
};
 
template<class T>
int QueueTP<T>::queuecount() const
{
    return items;
};
 
//Добавление элемента в очередь
template<class T>
bool QueueTP<T>::enqueue(const T & item)
{
    if (isfull())
    {
        return false;
    };
 
    Node * add = new Node;                                                                  //создание узла
 
    //При неудачном выполнении операция new генерирует исключение std::bad_alloc
    add->item = item;
    add->next = NULL;
    items++;
    if (front == NULL)
    {
        front = add;
    }
    else
    {
        rear->next = add;
    }
    rear = add;
    return true;
};
 
//Помещение элемента frint в переменную item и его удаление из очереди
template<class T>
bool QueueTP<T>::dequeue(T & item)
{
    if (front == NULL)
    {
        return false;
    };
    item = front->item;
    items--;
    Node * temp = front;
    front = front->next;
    delete temp;
    if (items == 0)
    {
        rear = NULL;
    };
    return true;
};
 
 
 
//Методы Worker
 
Worker::~Worker(){ ; }
 
//Защищённые методы
 
void Worker::Data() const
{
    cout << "Name: " << fullname << endl;
    cout << "Employee ID: " << id << endl;
}
 
void Worker::Get()
{
    getline(cin, fullname);
    cout << "Enter worker`s ID: ";
    cin >> id;
    while (cin.get() != '\n')
    {
        continue;
    }
}
 
//Методы Waiter
void Waiter::Set()
{
    cout << "Enter waitor`s name: ";
    Worker::Get();
    Get();
}
 
void Waiter::Show() const
{
    cout << "Category: waiter\n";
    Worker::Data();
    Data();
}
 
//Защищённые методы
void Waiter::Data() const
{
    cout << "Panache rating: " << panache << endl;
}
 
void Waiter::Get()
{
    cout << "Enter waiter`s panache rating: ";                                              //Ввод индекса элегантности официанта
    cin >> panache;
    while (cin.get() != '\n')
        continue;
}
 
//Методы Singer
char * Singer::pv[Singer::Vtypes] = { "other", "alto", "contralto",
"soprano", "bass", "baritone", "tenor" };
void Singer::Set()
{
    cout << "Enter singer`s name: ";
    Worker::Get();
    Get();
}
 
void Singer::Show() const
{
    cout << "Category: singer\n";
    Worker::Data();
    Data();
}
 
//Защищённые методы
void Singer::Data() const
{
    cout << "Vocal range: " << pv[voice] << endl;
}
 
void Singer::Get()
{
    cout << "Enter number for singer`s vocal range:\n";
    int i;
    for (i = 0; i < Vtypes; i++)
    {
        cout << i << ": " << pv[i] << " ";
        if (i % 4 == 3)
            cout << endl;
    }
    if (i % 4 == 0)
        cout << '\n';
    cin >> voice;
    while (cin.get() != '\n')
        continue;
}
 
//Методы SingerWaiter
void SingingWaiter::Data() const
{
    Singer::Data();
    Waiter::Data();
}
 
void SingingWaiter::Get()
{
    Waiter::Get();
    Singer::Get();
}
 
void SingingWaiter::Set()
{
    cout << "Enter singing waiter`s name: ";
    Worker::Get();
    Get();
}
 
void SingingWaiter::Show() const
{
    cout << "Category: singing waiter\n";
    Worker::Data();
    Data();
};
 
 
#endif // !TEMPLATE_CLASS_H_
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
//usemain.cpp
 
#include <iostream>
#include "template_class.h"
#include <cstring>
#include <Windows.h>
 
int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::strchr;
 
    int qs,counts;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    cout << "Enter size queue: ";
    cin >> qs;
 
    //Временный объект
    Worker *temp;
    QueueTP<Worker *> ochered(qs);
 
    for ( counts = 0; counts < qs; counts++)
    {
        char choice;
        cout << "Enter the employee category:\n"
             << "w: waiter s: singer "
                << "t: singing waiter q: quit\n";
            cin >> choice;
            while (strchr("wstq", choice) == NULL)
            {
                cout << "Please enter a w, s, t, or q: ";
                cin >> choice;
            }
            if (choice == 'q')
                break;
            switch (choice)
            {
            case 'w':
                temp = new Waiter;
                break;
            case 's':
                temp = new Singer;
                break;
            case 't':
                temp = new SingingWaiter;
                break;
            }
            cin.get();
            // Ввод данных в созданный объект:
            temp->Set();
            // Добавляем нового клиента в конец очереди, при это создается новый узел. На этом шаге как раз и осуществляется копирование данных, которые содержит временный объект, в часть данных нового узла:
            ochered.enqueue(temp);
    }//End for
 
    int ct;
    for (ct = 0; ct < counts; ct++)
    {
        ochered.dequeue(temp);
        temp->Show();
    }
 
    cout << "Bye.\n";
    system("pause");
    return EXIT_SUCCESS;
}
Это полностью работоспособный код если кто сделает функцию котораю из френд шадлона ворк выводит киньте мне образец на мыло andreypplk@mail.ru прошу прощение спойлер не нашол.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.07.2015, 15:50
Помогаю со студенческими работами здесь

Использование указателя на объект шаблонного класса в шаблонном классе.
Всем привет! Мне нужно реализовать граф. Начал с вершин и ребер, причем и ребра и вершины - шаблонные классы, для того чтобы и ребро и...

Шаблонный класс от шаблонного класса, ругается компоновщик
абстрактный класс Хэширования template &lt;class typeHashData, class typeHashIndex&gt; class AbstarctHash { private: public: ...

Классы-друзья (использование данных одного класса из другого)
Зарание спс ))) Я лаймер в С++ но учусь чтоб исправиться. И куда как не к вам обращаться за помощью =) в тяжкие дни свои. Проблема с...

Предусмотреть использование шаблонного класса для работы с различными типами данных
Собственно само задание. Преобразовать квадратную матрицу, осуществив поворот элементов вокруг центра матрицы на 90 градусов против...

Функция указатель на класс, определенный внутри шаблонного класса
Доброго времени суток! Помогите пожалуйста разобрать со следующим кодом: template &lt;class T&gt; class List{ class Node{ ...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Async/await в Swift: Асинхронное программировани­е в iOS
mobDevWorks 20.03.2025
Асинхронное программирование долго было одной из самых сложных задач для разработчиков iOS. В течение многих лет мы сражались с замыканиями, диспетчеризацией очередей и обратными вызовами, чтобы. . .
Сложность Колмогорова: Приёмы упрощения кода
ArchitectMsa 20.03.2025
Наверное, каждый программист хотя бы раз сталкивался с кодом, который напоминает запутанный лабиринт — чем дальше в него погружаешься, тем сложнее найти выход. И когда мы говорим о сложности кода, мы. . .
PostgreSQL в Kubernetes: Подготовка кластера и настройка
Mr. Docker 20.03.2025
Когда доходит до контейнеризации баз данных и особенно таких требовательных к ресурсам системах как PostgreSQL, многие команды до сих пор колеблются, прежде чем перенести их в контейнерную. . .
C++26: Индексирование пакетов и метапрограммиро­вание
bytestream 20.03.2025
Эволюция C++ продолжается стремительными темпами – каждый новый стандарт приносит функциональность, о которой мы мечтали годами. Звучит слишком громко? Если вы когда-либо боролись с вариадическими. . .
Состояние гонки в C#: подводные камни многопоточного программировани­я
UnmanagedCoder 20.03.2025
Что такое состояние гонки? Это ситуация, когда результат программы непредсказуемо меняется в зависимости от порядка выполнения потоков. Проще говоря, два или более потока пытаются одновременно. . .
Next.js для разработки React: преимущества серверного рендеринга
Reangularity 20.03.2025
Next. js решает классическую проблему React-приложений: медленную первоначальную загрузку и плохую индексацию поисковиками. Вместо того чтобы заставлять браузер пользователя выполнять всю работу по. . .
JUnit или TestNG: Выбираем Java-фреймворк для тестирования
Javaican 20.03.2025
История тестовых фреймворков в Java началась в конце 90-х, когда Кент Бек и Эрих Гамма разработали JUnit - инструмент, который перевернул представление разработчиков о модульном тестировании. JUnit. . .
Разбиваем монолит на два микросервиса и реализуем CI/CD
ArchitectMsa 20.03.2025
Когда команда растет, а функциональность монолита расширяется, поддерживать и развивать такую систему становится все труднее. Разработчики начинают тратить много времени на разбор сложных. . .
Python и PDF: Создание и редактирование файлов
py-thonny 20.03.2025
Работа с PDF-документами – одна из популярных задач в современной разработке. Python предлагает несколько инструментов для создания, чтения и редактирования PDF-файлов, среди которых особенно. . .
Корутины в Unity и производительно­сть WaitForSeconds
GameUnited 20.03.2025
Разработчики игр на Unity часто сталкиваются с вопросом: как выполнять действия через определённые промежутки времени, не блокируя основной поток игры? Тут как раз и приходят на помощь корутины —. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru
Выделить код Копировать код Сохранить код Нормальный размер Увеличенный размер