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

Дружественный шаблонный класс - C++

Восстановить пароль Регистрация
 
Мимино
 Аватар для Мимино
180 / 151 / 5
Регистрация: 22.05.2013
Сообщений: 435
Записей в блоге: 1
12.08.2013, 17:43     Дружественный шаблонный класс #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
#ifndef LISTND_H
#define LISTND_H
 
 
template <class NODETYPE>
class ListNode
{
    friend class List<NODETYPE>;
 
public:
    ListNode(const NODETYPE &);
    NODETYPE getData() const;
 
private:
    NODETYPE data;
    ListNode<NODETYPE> *nextPtr;
};
 
template <class NODETYPE>
ListNode<NODETYPE>::ListNode(const NODETYPE &info)
{
    data = info;
    nextPtr = 0;
}
 
template <class NODETYPE>
NODETYPE ListNode<NODETYPE>::getData() const { return data; }
 
#endif


Кликните здесь для просмотра всего текста
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
#ifndef LIST1_H
#define LIST1_H
#include <iostream>
#include <assert.h>
#include "listnd.h"
using namespace std;
 
 
 
template <class NODETYPE>
class List
{
public:
    List();
    ~List();
    void insertAtFront(const NODETYPE &);
    void insertAtBack(const NODETYPE &);
    int removeFromFront(NODETYPE &);
    int removeFromBack(NODETYPE &);
    int isEmpty() const;
    void print() const;
 
private:
    ListNode<NODETYPE> *firstPtr;
    ListNode<NODETYPE> *lastPtr;
    ListNode<NODETYPE> *getNewNode(const NODETYPE &);
};
 
template <class NODETYPE>
List<NODETYPE>::List() { firstPtr = lastPtr = 0; }
 
template <class NODETYPE>
List<NODETYPE>::~List()
{
    if (!isEmpty())
    {
        cout << "Удаление узлов... " << endl;
        ListNode<NODETYPE> *currentPtr = firstPtr, *tempPtr;
 
        while (currentPtr != 0)
        {
            tempPtr = currentPtr;
            cout << tempPtr->data << endl;
            currentPtr = currentPtr->nextPtr;
            delete tempPtr;
        }
    }
 
    cout << "Все узлы удалены" << endl << endl;
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtFront(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        newPtr->nextPtr = firstPtr;
        firstPtr = newPtr;
    }
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtBack(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        lastPtr->nextPtr = newPtr;
        lastPtr = newPtr;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromFront(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = firstPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
            firstPtr = firstPtr->nextPtr;
        value = tempPtr->data;
        delete tempPtr;
        return 1;
    }
 
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromBack(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = lastPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
        {
            ListNode<NODETYPE> *currentPtr = firstPtr;
 
            while (currentPtr->nextPtr != lastPtr)
                currentPtr = currentPtr->nextPtr;
 
            lastPtr = currentPtr;
            currentPtr->nextPtr = 0;
        }
 
        value = tempPtr->data;
        delete tempPtr;
        return 1;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::isEmpty() const { return firstPtr == 0; }
 
template <class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value)
{
    ListNode<NODETYPE> *ptr = new ListNode<NODETYPE>(value);
    assert(ptr != 0);
    return ptr;
}
 
template <class NODETYPE>
void List<NODETYPE>::print() const
{
    if (isEmpty())
    {
        cout << "Список пуст" << endl << endl;
        return;
    }
 
    ListNode<NODETYPE> *currentPtr = firstPtr;
    cout << "Список состоит из: ";
 
    while (currentPtr != 0)
    {
        cout << currentPtr->data << ' ';
        currentPtr = currentPtr->nextPtr;
    }
 
    cout << endl << endl;
}
 
#endif


Кликните здесь для просмотра всего текста
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
#include "stdafx.h"
#include <iostream>
#include "list1.h"
using namespace std;
 
 
void testIntegerList();
void testFloatList();
void instructions();
 
int main()
{
    setlocale(LC_ALL, "Russian");
 
    testIntegerList();
    testFloatList();
 
    system("pause");
    return 0;
}
 
 
void testIntegerList()
{
    cout << "Проверка списка целых чисел" << endl;
    List<int> integerList;
 
    instructions();
 
    int choice, value;
 
    do
    {
        cout << "? ";
        cin >> choice;
 
        switch (choice)
        {
            case 1:
                cout << "Введите целое: ";
                cin >> value;
                integerList.insertAtFront(value);
                integerList.print();
                break;
 
            case 2:
                cout << "Введите целое: ";
                cin >> value;
                integerList.insertAtBack(value);
                integerList.print();
                break;
 
            case 3:
                if (integerList.removeFromFront(value))
                    cout << value << " удаляется из списка" << endl;
 
                integerList.print();
                break;
 
            case 4:
                if (integerList.removeFromBack(value))
                    cout << value << " удаляется из списка" << endl;
 
                integerList.print();
                break;
        }
    } while (choice != 5);
 
    cout << "Конец проверки списка целых чисел" << endl;
}
 
 
void testFloatList()
{
    cout << "Проверка списка чисел с плавающей запятой" << endl;
    List<float> floatList;
 
    instructions();
 
    int choice;
    float value;
 
    do
    {
        cout << "? ";
        cin >> choice;
 
        switch (choice)
        {
            case 1:
                cout << "Введите число с плавающей запятой: ";
                cin >> value;
                floatList.insertAtFront(value);
                floatList.print();
                break;
 
            case 2:
                cout << "Введите число с плавающей запятой: ";
                cin >> value;
                floatList.insertAtBack(value);
                floatList.print();
                break;
 
            case 3:
                if (floatList.removeFromFront(value))
                    cout << value << " удаляется из списка" << endl;
 
                floatList.print();
                break;
 
            case 4:
                if (floatList.removeFromBack(value))
                    cout << value << " удаляется из списка" << endl;
 
                floatList.print();
                break;
        }
    } while (choice != 5);
 
    cout << "Конец проверки списка чисел с плавающей запятой" << endl;
}
 
 
void instructions()
{
    cout << "Выберите: " << endl
         << "1 - вставить в начало списка" << endl
         << "2 - вставить в конец списка" << endl
         << "3 - удалить из начала списка" << endl
         << "4 - удалить из конца списка" << endl
         << "5 - завершить обработку списка" << endl;
}


А вот и чудо-список ошибок:
c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\listnd.h(9): error C2059: syntax error : '<'
1> c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\listnd.h(18) : see reference to class template instantiation 'ListNode<NODETYPE>' being compiled
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\listnd.h(9): error C2238: unexpected token(s) preceding ';'
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(28): error C2989: 'List' : class template has already been declared as a non-class template
1> c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\listnd.h(9) : see declaration of 'List'
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(11): error C3857: 'List': multiple template parameter lists are not allowed
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(31): error C2988: unrecognizable template declaration/definition
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(31): error C2059: syntax error : '<'
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(34): error C2588: '::~List' : illegal global destructor
1>c:\users\mimino\documents\проекты\дейтл\глава 15\1 ex\1 ex\list1.h(34): fatal error C1903: unable to recover from previous error(s); stopping compilation
Методом проб и ошибок выяснил, что ошибка кроется в объявлении дружественного класса. Исправить не могу. Буду очень признателен за помощь и разъяснения.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.08.2013, 17:43     Дружественный шаблонный класс
Посмотрите здесь:

дружественный класс C++
Переделать класс в шаблонный класс C++
Дружественный класс (код внутри) C++
Дружественный класс C++
Шаблонный класс C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Valentina
66 / 66 / 3
Регистрация: 13.05.2012
Сообщений: 130
12.08.2013, 18:00     Дружественный шаблонный класс #2
Это шаблон, а не класс, поэтому весь код имплементации надо втащить в тот же h-файл
В новых версиях компиляторов идут подвижки к тому, чтобы разрешить хранение кода шаблона отдельно от объявления шаблона, но судя по всему пока это не действует
Мимино
 Аватар для Мимино
180 / 151 / 5
Регистрация: 22.05.2013
Сообщений: 435
Записей в блоге: 1
12.08.2013, 18:03  [ТС]     Дружественный шаблонный класс #3
Цитата Сообщение от Valentina Посмотреть сообщение
Это шаблон, а не класс, поэтому весь код имплементации надо втащить в тот же h-файл
В новых версиях компиляторов идут подвижки к тому, чтобы разрешить хранение кода шаблона отдельно от объявления шаблона, но судя по всему пока это не действует
Объявления класса и реализация находятся в 1-м файле. Совмещение в 1-м файле 2-х шаблонов проблему не решает.
Schizorb
 Аватар для Schizorb
508 / 460 / 16
Регистрация: 07.04.2012
Сообщений: 865
Записей в блоге: 1
Завершенные тесты: 1
12.08.2013, 18:08     Дружественный шаблонный класс #4
Мимино, вот весь заголовочный файл:

Кликните здесь для просмотра всего текста
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
#ifndef LISTND_H
#define LISTND_H
 
#include <iostream>
#include <assert.h>
 
using namespace std;
 
template <class NODETYPE>
class List;
 
template <class NODETYPE>
class ListNode
{
    friend class List<NODETYPE>;
 
public:
    ListNode(const NODETYPE &);
    NODETYPE getData() const;
 
private:
    NODETYPE data;
    ListNode<NODETYPE> *nextPtr;
};
 
template <class NODETYPE>
class List
{
public:
    List();
    ~List();
    void insertAtFront(const NODETYPE &);
    void insertAtBack(const NODETYPE &);
    int removeFromFront(NODETYPE &);
    int removeFromBack(NODETYPE &);
    int isEmpty() const;
    void print() const;
 
private:
    ListNode<NODETYPE> *firstPtr;
    ListNode<NODETYPE> *lastPtr;
    ListNode<NODETYPE> *getNewNode(const NODETYPE &);
};
 
 
template <class NODETYPE>
ListNode<NODETYPE>::ListNode(const NODETYPE &info)
{
    data = info;
    nextPtr = 0;
}
 
template <class NODETYPE>
NODETYPE ListNode<NODETYPE>::getData() const { return data; }
 
template <class NODETYPE>
List<NODETYPE>::List() { firstPtr = lastPtr = 0; }
 
template <class NODETYPE>
List<NODETYPE>::~List()
{
    if (!isEmpty())
    {
        cout << "Удаление узлов... " << endl;
        ListNode<NODETYPE> *currentPtr = firstPtr, *tempPtr;
 
        while (currentPtr != 0)
        {
            tempPtr = currentPtr;
            cout << tempPtr->data << endl;
            currentPtr = currentPtr->nextPtr;
            delete tempPtr;
        }
    }
 
    cout << "Все узлы удалены" << endl << endl;
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtFront(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        newPtr->nextPtr = firstPtr;
        firstPtr = newPtr;
    }
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtBack(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        lastPtr->nextPtr = newPtr;
        lastPtr = newPtr;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromFront(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = firstPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
            firstPtr = firstPtr->nextPtr;
        value = tmpPtr->data;
        delete tmpPtr;
        return 1;
    }
 
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromBack(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = lastPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
        {
            ListNode<NODETYPE> *currentPtr = firstPtr;
 
            while (currentPtr->nextPtr != lastPtr)
                currentPtr = currentPtr->nextPtr;
 
            lastPtr = currentPtr;
            currentPtr->nextPtr = 0;
        }
 
        value = tmpPtr->data;
        delete tmpPtr;
        return 1;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::isEmpty() const { return firstPtr == 0; }
 
template <class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value)
{
    ListNode<NODETYPE> *ptr = new ListNode<NODETYPE>(value);
    assert(ptr != 0);
    return ptr;
}
 
template <class NODETYPE>
void List<NODETYPE>::print() const
{
    if (isEmpty())
    {
        cout << "Список пуст" << endl << endl;
        return;
    }
 
    ListNode<NODETYPE> *currentPtr = firstPtr;
    cout << "Список состоит из: ";
 
    while (currentPtr != 0)
    {
        cout << currentPtr->data << ' ';
        currentPtr = currentPtr->nextPtr;
    }
 
    cout << endl << endl;
}
 
#endif


Понадобилось еще предварительное объявление шаблонного класса List. Можно было еще объявить дружественный класс с другим именем параметра:

C++
1
2
template <class T>
friend class List;
Мимино
 Аватар для Мимино
180 / 151 / 5
Регистрация: 22.05.2013
Сообщений: 435
Записей в блоге: 1
12.08.2013, 18:13  [ТС]     Дружественный шаблонный класс #5
Цитата Сообщение от Schizorb Посмотреть сообщение
Мимино, вот весь заголовочный файл:

Кликните здесь для просмотра всего текста
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
#ifndef LISTND_H
#define LISTND_H
 
#include <iostream>
#include <assert.h>
 
using namespace std;
 
template <class NODETYPE>
class List;
 
template <class NODETYPE>
class ListNode
{
    friend class List<NODETYPE>;
 
public:
    ListNode(const NODETYPE &);
    NODETYPE getData() const;
 
private:
    NODETYPE data;
    ListNode<NODETYPE> *nextPtr;
};
 
template <class NODETYPE>
class List
{
public:
    List();
    ~List();
    void insertAtFront(const NODETYPE &);
    void insertAtBack(const NODETYPE &);
    int removeFromFront(NODETYPE &);
    int removeFromBack(NODETYPE &);
    int isEmpty() const;
    void print() const;
 
private:
    ListNode<NODETYPE> *firstPtr;
    ListNode<NODETYPE> *lastPtr;
    ListNode<NODETYPE> *getNewNode(const NODETYPE &);
};
 
 
template <class NODETYPE>
ListNode<NODETYPE>::ListNode(const NODETYPE &info)
{
    data = info;
    nextPtr = 0;
}
 
template <class NODETYPE>
NODETYPE ListNode<NODETYPE>::getData() const { return data; }
 
template <class NODETYPE>
List<NODETYPE>::List() { firstPtr = lastPtr = 0; }
 
template <class NODETYPE>
List<NODETYPE>::~List()
{
    if (!isEmpty())
    {
        cout << "Удаление узлов... " << endl;
        ListNode<NODETYPE> *currentPtr = firstPtr, *tempPtr;
 
        while (currentPtr != 0)
        {
            tempPtr = currentPtr;
            cout << tempPtr->data << endl;
            currentPtr = currentPtr->nextPtr;
            delete tempPtr;
        }
    }
 
    cout << "Все узлы удалены" << endl << endl;
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtFront(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        newPtr->nextPtr = firstPtr;
        firstPtr = newPtr;
    }
}
 
template <class NODETYPE>
void List<NODETYPE>::insertAtBack(const NODETYPE &value)
{
    ListNode<NODETYPE> *newPtr = getNewNode(value);
 
    if (isEmpty())
        firstPtr = lastPtr = newPtr;
    else
    {
        lastPtr->nextPtr = newPtr;
        lastPtr = newPtr;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromFront(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = firstPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
            firstPtr = firstPtr->nextPtr;
        value = tmpPtr->data;
        delete tmpPtr;
        return 1;
    }
 
}
 
template <class NODETYPE>
int List<NODETYPE>::removeFromBack(NODETYPE &value)
{
    if (isEmpty())
        return 0;
    else
    {   
        ListNode<NODETYPE> *tmpPtr = lastPtr;
        if (firstPtr == lastPtr)
            firstPtr = lastPtr = 0;
        else
        {
            ListNode<NODETYPE> *currentPtr = firstPtr;
 
            while (currentPtr->nextPtr != lastPtr)
                currentPtr = currentPtr->nextPtr;
 
            lastPtr = currentPtr;
            currentPtr->nextPtr = 0;
        }
 
        value = tmpPtr->data;
        delete tmpPtr;
        return 1;
    }
}
 
template <class NODETYPE>
int List<NODETYPE>::isEmpty() const { return firstPtr == 0; }
 
template <class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value)
{
    ListNode<NODETYPE> *ptr = new ListNode<NODETYPE>(value);
    assert(ptr != 0);
    return ptr;
}
 
template <class NODETYPE>
void List<NODETYPE>::print() const
{
    if (isEmpty())
    {
        cout << "Список пуст" << endl << endl;
        return;
    }
 
    ListNode<NODETYPE> *currentPtr = firstPtr;
    cout << "Список состоит из: ";
 
    while (currentPtr != 0)
    {
        cout << currentPtr->data << ' ';
        currentPtr = currentPtr->nextPtr;
    }
 
    cout << endl << endl;
}
 
#endif


Понадобилось еще предварительное объявление шаблонного класса List. Можно было еще объявить дружественный класс с другим именем параметра:

C++
1
2
template <class T>
friend class List;
Делал так же, только без предварительного объявления класса. Вот не идут у меня шаблоны как то. Спасибо. скомпилилось, буду пробовать.
Yandex
Объявления
12.08.2013, 18:13     Дружественный шаблонный класс
Ответ Создать тему
Опции темы

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