Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
DESergik
1 / 1 / 0
Регистрация: 26.12.2012
Сообщений: 17
1

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

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

Всем привет!

Изучаю книгу "Прата С. - Язык программирования С++. Лекции и упражнения". Разобрал тему шаблоны классов и в заданиях для тренировки было предложено переделать класс очереди в шаблонный класс. Очередь реализована при помощи связанного списка (точнее односвязного). Для его работы в классе присутствует вложенное определение структуры 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)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
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; class ConcreteConverter { T _value; long long _maxValue;...

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

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

10
hoggy
Эксперт С++
7109 / 3155 / 650
Регистрация: 15.11.2014
Сообщений: 7,250
Завершенные тесты: 1
03.01.2015, 18:37 2
Лучший ответ Сообщение было отмечено 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
DESergik
1 / 1 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 22:44  [ТС] 3
hoggy, в этой строчке я пытаюсь создать нулевой указатель на структуру типа Node для его использования в цикле for ниже. При помощи цикла for затем я пытаюсь "перебрать" все узлы - от *front до *rear и вывести данные, которые они содержат (член item структуры Node).

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

Добавлено через 3 часа 10 минут
Автоматическое выведение типа это удобно конечно, но всё таки очень хочется узнать, как вручную правильно объявить тип для переменной i. Как ни пытался, не смог этого сделать. Поэтому вопрос ещё открыт.
0
hoggy
Эксперт С++
7109 / 3155 / 650
Регистрация: 15.11.2014
Сообщений: 7,250
Завершенные тесты: 1
03.01.2015, 22:49 4
Цитата Сообщение от DESergik Посмотреть сообщение
как вручную правильно объявить тип для переменной i. Как ни пытался, не смог этого сделать. Поэтому вопрос ещё открыт.
Это я для кого оставил?

Цитата Сообщение от hoggy Посмотреть сообщение
typename T::Node* i=nullptr;
1
03.01.2015, 22:49
DESergik
1 / 1 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 23:02  [ТС] 5
Цитата Сообщение от hoggy Посмотреть сообщение
Это я для кого оставил?
Сообщение от hoggy
typename T::Node* i=nullptr;
hoggy, понял, извиняюсь за свою невнимательность.
Только запись данной строчки мне не очень понятна... Ведь вложенная структура Node - это член класса QueueTP, почему данный член нельзя использовать, например с таким синтаксисом:
C++
1
q.Node *i=nullptr; // Не работает
Не понимаю этот момент
0
hoggy
Эксперт С++
7109 / 3155 / 650
Регистрация: 15.11.2014
Сообщений: 7,250
Завершенные тесты: 1
03.01.2015, 23:14 6
Цитата Сообщение от DESergik Посмотреть сообщение
Ведь вложенная структура Node - это член класса QueueTP, почему данный член нельзя использовать, например с таким синтаксисом:
Во-первых, вложенная структура не является членом класса.
Она является самой обычной структурой, просто объявлена в пространстве имени класса-хозяина. Вот и все.

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

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

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

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

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

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

Понимаете?

Хотите обратиться к структуре которая принадлежит классу - так и обращайтесь к самому классу.
1
DESergik
1 / 1 / 0
Регистрация: 26.12.2012
Сообщений: 17
03.01.2015, 23:51  [ТС] 7
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
Эксперт С++
7109 / 3155 / 650
Регистрация: 15.11.2014
Сообщений: 7,250
Завершенные тесты: 1
04.01.2015, 00:12 8
Цитата Сообщение от 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
DESergik
1 / 1 / 0
Регистрация: 26.12.2012
Сообщений: 17
04.01.2015, 12:19  [ТС] 9
hoggy, большое спасибо за объяснение. Теперь разобрался
0
andreypplk
1 / 1 / 0
Регистрация: 08.02.2014
Сообщений: 29
14.07.2015, 15:13 10
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
andreypplk
1 / 1 / 0
Регистрация: 08.02.2014
Сообщений: 29
16.07.2015, 15:50 11
Так ни кто и не помог но я сделал правда данные из очереди выводятся на экран после удаления из очереди.
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
16.07.2015, 15:50
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.07.2015, 15:50

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

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

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


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru