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

Шаблонный класс List - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 33, средняя оценка - 4.67
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
17.11.2011, 23:21     Шаблонный класс List #1
Имеется 2 шаблонных класса List и Node. Один объявлен другом другого. По идее должно работать, но у компилятора другое мнение на этот счет:
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall List<int>::PrintListForward(void)const " (?PrintListForward@?$List@H@@QBEXXZ) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall List<int>::AddBegining(int)" (?AddBegining@?$List@H@@QAEXH@Z) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall List<int>::List<int>(void)" (??0?$List@H@@QAE@XZ) referenced in function _main
1>C:\Users\selver\documents\visual studio 2010\Projects\List_One\Debug\List_One.exe : fatal error LNK1120: 3 unresolved externals

Класс Node:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef NODE_H
#define NODE_H
 
template <class T>
class Node
{
public:
    Node(T,Node<T>*,Node<T>*);
    Node(T);
private:
    Node<T> * next;
    Node<T> * last;
    int key;
    T data;
};
 
#endif NODE_H
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Node.h"
template <class T>
Node<T>::Node(T data,Node * next,Node * last)
{
    this->data=data;
    this->next=next;
    this->last=last;
}
 
template <class T>
Node<T>::Node(T data)
{
    this->data=data;
}
класс List:
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
#ifndef LIST_H
#define LIST_H
#include "Node.h"
 
template <class T>
class List
{
public:
    friend class Node<T>;
    List();
    void AddNodeEnd(T data);
    void AddBegining(T data);
    void deleteNodeEnd();
    void deleteNodeBegin();
    int find(int) const;
    void PrintListForward() const;
    void PrintListBack() const;
    void numNode() const;
private:
    Node<T> * head;
    Node<T> * temp;
};
 
#endif LIST_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
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
#include "List.h"
#include "Node.h"
#include<iostream>
 
template <class T>
List<T>::List():
head(NULL),
temp(NULL)
{}
 
template <class T>
void List<T>::AddNodeEnd(T data)
{
    Node<T> * nd=new Node<T>(data,NULL,temp);
    temp=nd;
    if (head)
    {
        Node<T>* current=head;
        while(current->next)
            current=current->next;
            current->last=nd;
    }
    else head=nd;
    numNode();
}
 
template <class T>
void List<T>::AddBegining(T data)
{
    Node<T> * nd=new Node<T>(data);
    if(head)
    {
        Node<T> * tmpt=head;
        head=nd;
        nd->next=tmpt;
    }
    else 
    {
        head=nd;
        nd->next=NULL;
    }
    numNode();
}
 
template <class T>
void List<T>::deleteNodeEnd()
{
    if (temp)
    {
        Node<T> * current=temp;
        current=current->last;
        delete current->next;
        current->next=NULL;
    }
    else
    std::cout<<"list is empty";
}
 
template <class T>
void List<T>::deleteNodeBegin()
{
    if (head)
    {
        Node<T> * tmpt;
        tmpt=head;
        tmpt=tmpt->next;
        delete head;
        head=tmpt;
    }
    else
    std::cout<<"list is empty";
}
 
template <class T>
int List<T>::find(int k) const
{
    Node<T>* current;
    current=head;
    while(current)
    {
        if (current->key==k)
            return current->data;
        current=current->next;
    }
}
 
template <class T>
void List<T>::PrintListForward() const
{
    Node<T> * current=head;
    while(current)
    {
        std::cout<<current->data<<" ";
        current=current->next;
    }
}
 
template <class T>
void List<T>::PrintListBack() const
{
    Node<T> * current=temp;
    while(current)
    {
        std::cout<<current->key<<" "<<current->data;
        current->last;
    }
}
 
template <class T>
void List<T>::numNode() const
{
    Node<T> * counter=head;
    int i=0;
    while (counter)
    {
        counter->key=++i;
        counter=counter->next;
    }
}
main:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include"Node.h"
#include "List.h"
using namespace std;
 
int main()
{
    List<int> n;
    n.AddBegining(12);
    n.AddBegining(45);
    n.AddBegining(10);
    n.AddBegining(70);
    n.AddBegining(0);
    n.AddBegining(55);
    n.PrintListForward();
    return 0;
}
Без шаблонов все работало.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
lemegeton
 Аватар для lemegeton
2910 / 1339 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
17.11.2011, 23:24     Шаблонный класс List #2
Шаблонный класс нельзя разделять на заголовок и модуль. Это так не работает.
prazuber
108 / 108 / 3
Регистрация: 29.04.2010
Сообщений: 240
17.11.2011, 23:32     Шаблонный класс List #3
Да, действительно, шаблонные класы надо сразу целиком писать в хедер-файлах. Например, файл Node.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
#ifndef NODE_H
#define NODE_H
 
template <class T>
class Node
{
public:
 
    Node(T data,Node * next,Node * last)
    {
        this->data=data;
        this->next=next;
        this->last=last;
    }
 
    Node(T data)
    {
        this->data=data;
    }
 
private:
    Node *next;
    Node *last;
    int key;
    T data;
};
 
#endif // NODE_H
Аналогично со вторым файлом.
Bers
Заблокирован
18.11.2011, 00:46     Шаблонный класс List #4
Разделять можно. Нужно только знать как. Если не знаешь - пиши все в хэдэр.
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,131
18.11.2011, 01:00     Шаблонный класс List #5
Цитата Сообщение от PraZuBeR Посмотреть сообщение
Node(T data,Node * next,Node * last)
{
this->data=data;
this->next=next;
this->last=last;
}
можно отдельно вынести, но только чтобы в одном хэдере.
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
18.11.2011, 13:25  [ТС]     Шаблонный класс List #6
Передалал, но по-прежнему не компилируется. Выдает:
1>c:\users\selver\documents\visual studio 2010\projects\list_one\list_one\list.h(120): error C2955: 'Node' : use of class template requires template argument list
1> c:\users\selver\documents\visual studio 2010\projects\list_one\list_one\node.h(8) : see declaration of 'Node'
1> c:\users\selver\documents\visual studio 2010\projects\list_one\list_one\main.cpp(8) : see reference to class template instantiation 'List<T>' being compiled
1> with
1> [
1> T=int
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 NODE_H
#define NODE_H
 
 
 
template <class T>
class Node
{
public:
    Node(T data,Node* next,Node* last)
{
    this->data=data;
    this->next=next;
    this->last=last;
}
    
Node(T data)
{
    this->data=data;
}
 
private:
    Node * next;
    Node * last;
    int key;
    T data;
};
 
#endif NODE_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
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
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include "Node.h"
 
 
template <class T>
class List
{
public:
    friend class Node<T>;
    List():
    head(NULL),
    temp(NULL)
    {}
 
    void AddNodeEnd(T data)
    {
        Node * nd=new Node(data,NULL,temp);
    temp=nd;
    if (head)
    {
        Node* current=head;
        while(current->next)
            current=current->next;
            current->last=nd;
    }
    else head=nd;
    numNode();
    }
 
    void AddBegining(T data)
    {
            Node* nd=new Node(data);
    if(head)
    {
        Node* tmpt=head;
        head=nd;
        nd->next=tmpt;
    }
    else 
    {
        head=nd;
        nd->next=NULL;
    }
    numNode();
    }
 
    void deleteNodeEnd()
    {
            if (temp)
    {
        Node* current=temp;
        current=current->last;
        delete current->next;
        current->next=NULL;
    }
    else
    std::cout<<"list is empty";
    }
 
    void deleteNodeBegin()
    {
            if (head)
    {
        Node* tmpt;
        tmpt=head;
        tmpt=tmpt->next;
        delete head;
        head=tmpt;
    }
    else
    std::cout<<"list is empty";
    }
 
    T find(int key) const
    {
            Node* current;
    current=head;
    while(current)
    {
        if (current->key==k)
            return current->data;
        current=current->next;
    }
    }
 
    void PrintListForward() const
    {
        Node* current=head;
    while(current)
    {
        std::cout<<current->data<<" ";
        current=current->next;
    }
    }
 
    void PrintListBack() const
    {
            Node* current=temp;
    while(current)
    {
        std::cout<<current->key<<" "<<current->data;
        current->last;
    }
    }
 
    void numNode() const
    {
            Node* counter=head;
    int i=0;
    while (counter)
    {
        counter->key=++i;
        counter=counter->next;
    }
    }
 
private:
    Node* head;
    Node* temp;
};
 
 
 
#endif LIST_H
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include"Node.h"
#include "List.h"
using namespace std;
 
int main()
{
    List<int> n;
    n.AddBegining(12);
    n.AddBegining(45);
    n.AddBegining(10);
    n.AddBegining(70);
    n.AddBegining(0);
    n.AddBegining(55);
    n.PrintListForward();
    return 0;
}
Попробывал писать в List:
Node<T>* head, Node<T>* temp и в функциях заменять Node на Node<T>, ошибок еще больше. Вопрос: так как все таки правильно Node * head, или Node<T>* head?
Bers
Заблокирован
18.11.2011, 13:31     Шаблонный класс List #7
ramarren14, закинь всю реализацию своего шаблона в тот же файл хэдэр, где идет объявление самого шаблона.

И объявление, и реализация шаблона находятся в одном файле хэдэре.
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
18.11.2011, 13:38  [ТС]     Шаблонный класс List #8
Так? Все равно те же ошибки выдает.
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
#ifndef LIST_H
#define LIST_H
#include <iostream>
 
template <class T>
class Node
{
public:
    Node(T data,Node* next,Node* last)
{
    this->data=data;
    this->next=next;
    this->last=last;
}
    
Node(T data)
{
    this->data=data;
}
 
private:
    Node * next;
    Node * last;
    int key;
    T data;
};
 
 
 
template <class T>
class List
{
public:
    friend class Node<T>;
    List():
    head(NULL),
    temp(NULL)
    {}
 
    void AddNodeEnd(T data)
    {
        Node * nd=new Node(data,NULL,temp);
    temp=nd;
    if (head)
    {
        Node* current=head;
        while(current->next)
            current=current->next;
            current->last=nd;
    }
    else head=nd;
    numNode();
    }
 
    void AddBegining(T data)
    {
            Node* nd=new Node(data);
    if(head)
    {
        Node* tmpt=head;
        head=nd;
        nd->next=tmpt;
    }
    else 
    {
        head=nd;
        nd->next=NULL;
    }
    numNode();
    }
 
    void deleteNodeEnd()
    {
            if (temp)
    {
        Node* current=temp;
        current=current->last;
        delete current->next;
        current->next=NULL;
    }
    else
    std::cout<<"list is empty";
    }
 
    void deleteNodeBegin()
    {
            if (head)
    {
        Node* tmpt;
        tmpt=head;
        tmpt=tmpt->next;
        delete head;
        head=tmpt;
    }
    else
    std::cout<<"list is empty";
    }
 
    T find(int key) const
    {
            Node* current;
    current=head;
    while(current)
    {
        if (current->key==k)
            return current->data;
        current=current->next;
    }
    }
 
    void PrintListForward() const
    {
        Node* current=head;
    while(current)
    {
        std::cout<<current->data<<" ";
        current=current->next;
    }
    }
 
    void PrintListBack() const
    {
            Node* current=temp;
    while(current)
    {
        std::cout<<current->key<<" "<<current->data;
        current->last;
    }
    }
 
    void numNode() const
    {
            Node* counter=head;
    int i=0;
    while (counter)
    {
        counter->key=++i;
        counter=counter->next;
    }
    }
 
private:
    Node* head;
    Node* temp;
};
 
 
 
#endif LIST_H
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include "List.h"
using namespace std;
 
int main()
{
    List<int> n;
    n.AddBegining(12);
    n.AddBegining(45);
    n.AddBegining(10);
    n.AddBegining(70);
    n.AddBegining(0);
    n.AddBegining(55);
    n.PrintListForward();
    return 0;
}
Bers
Заблокирован
18.11.2011, 13:46     Шаблонный класс List #9
Да. Примерно так.

Если не знаешь, как разбивать объявление класса шаблона и реализацию на файлы - всегда пиши все в одном файле.

Ладно, с этим разобрались.

Читать твой код по меньшей мере не приятно, потому что ты не соблюдаешь отступы. Нечитабельно.

Что говорит теперь компилятор?

Добавлено через 5 минут
Цитата Сообщение от ramarren14 Посмотреть сообщение
Node * nd=new Node(data,NULL,temp);
Ну вот здесь например.
Node у тебя - это шаблон, который имеет вид: Node<T>

То есть, Node<int> и Node<std::string> это два принципиально разных типа объектов.
Они занимают разную память.

Ты скармливаешь оператору new какой то непонятный Node
Как он без параметра догадается, для какого типа ему выделять память?
Как он догадается, сколько памяти будит весить объект, если он не знает параметра шаблона?

В общем, все подобные ошибки.
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
18.11.2011, 13:48  [ТС]     Шаблонный класс List #10
Ну вот я про это и спрашивал. То есть правильно Node<T>* nd=new Node<T>(data,NULL,temp) ?
Bers
Заблокирован
18.11.2011, 13:49     Шаблонный класс List #11
Цитата Сообщение от ramarren14 Посмотреть сообщение
Ну вот я про это и спрашивал. То есть правильно Node<T>* nd=new Node<T>(data,NULL,temp) ?
Да. Я просто хочу, что б ты понял саму идею

Тогда у тебя уже не будит возникать вопросов, когда нужно указывать параметр шаблона, а когда не обязательно.
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
18.11.2011, 14:07  [ТС]     Шаблонный класс List #12
Исправил и скомплировал, убрав private в Node, так как компилятор показывал:
1>c:\users\selver\documents\visual studio 2010\projects\list_one\list_one\list.h(62): error C2248: 'Node<T>::next' : cannot access private member declared in class 'Node<T>'
Ну и в таком духе.
Поставил public, сразу заработало.
Странно, почему так происходит, я ведь поставил friend class Node<T>??
Bers
Заблокирован
18.11.2011, 14:16     Шаблонный класс List #13
внимательно изучи этот код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template<class T> class Manager; //предварительное объявление
 
template<class T> 
class Test
{
    friend class Manager<T>;
    int a;  
};
 
template<class T> class Manager
{
    Test<T> myData;
public:
    Manager() { myData.a=10; }
};
 
int main()
{
    Manager<int> check;
    return 0;
}

/зы у тебя в коде присутствует архитектурный фейл. То есть, работать то такой код может быть и будит, но... так делать нельзя. Ты пока ещё не понял в чем заключается идея ООП - "разделяй и властвуй". У тебя по стилю ещё ощущается суржик
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
24.11.2011, 23:27     Шаблонный класс List #14
Как разделить шаблон на заголовок и модуль:
Создаешь отдельный хедер, пишешь туда прототип своего шаблона. Далее создаешь отдельный cpp, подключаешь туда хедер шаблона, прописываешь #pragma once, пишешь там реализации. Потом в файлах, где используется шаблон, подключай cpp-файл
Bers
Заблокирован
24.11.2011, 23:31     Шаблонный класс List #15
Цитата Сообщение от Riderik Посмотреть сообщение
Как разделить шаблон на заголовок и модуль:
Создаешь отдельный хедер, пишешь туда прототип своего шаблона. Далее создаешь отдельный cpp, подключаешь туда хедер шаблона, прописываешь #pragma once, пишешь там реализации. Потом в файлах, где используется шаблон, подключай cpp-файл
И где здесь модульность?
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
24.11.2011, 23:32     Шаблонный класс List #16
Bers, ну код-то в разных файлах
Bers
Заблокирован
24.11.2011, 23:35     Шаблонный класс List #17
Цитата Сообщение от Riderik Посмотреть сообщение
Bers, ну код-то в разных файлах
Да можно хоть по 10ти файликам разбить. И тупо все десять файликов инклудить в один.
Только модульность то тут причем?


Раздельная компиляция, это когда единица трансляции компилируется отдельно, и потом компонуется со всеми остальными.

#include"someFile.cpp" только с толку собъёт. Это что вообще такое? хэдэр? Или единица трансляции? А если это единица трансляции, на кой чорт её инклюдить столь явным образом?
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
24.11.2011, 23:37     Шаблонный класс List #18
Bers, всё равно красивее выходит, чем реализация в хедере
Bers
Заблокирован
24.11.2011, 23:51     Шаблонный класс List #19
Цитата Сообщение от Riderik Посмотреть сообщение
Bers, всё равно красивее выходит, чем реализация в хедере
Ну вообще, вот я сам так и делаю - реализацию в отдельный файл выношу по возможности.
Но не нужно называть спп то, что им на самом деле не является. Это может сбить с толку.

Я обычно делаю так:

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
#ifndef TClass_h
#define TClass_h
 
//TClass.h   Главный хэдер шаблонного класса
//имя хэдэра всегда совпадает с именем самого класса
 
 
template<class T>
class TClass
{
    //пошли методы и все остальное
};
 
#include "Impl_TClass.h" //реализация методов шаблона.
 
//причем согласно нотации принято,
// что Impl_имяКласса.h всегда означает,
// что данный хэдэр содержит неккую реализацию класса.
 
//А буковка 'T' в начале имени класса Tкласс
//означает, что тип данной сущности - шаблон.
//Поэтому, читая название инклюда, у любого
//кто знаком с моей нотации не будит никаких сомнений
//что в конце объявления самого шаблона,
//инклюдиццо реализация этого шаблона.
 
//А для тех, кто в танке
//я всегда оставляю комментарий.
 
 
#endif
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.11.2011, 14:35     Шаблонный класс List
Еще ссылки по теме:

Шаблонный класс C++
Создать динамический шаблонный класс односвязный список - List C++
C++ шаблонный класс

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

Или воспользуйтесь поиском по форуму:
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
25.11.2011, 14:35     Шаблонный класс List #20
Bers, Изврат все же. .tcc еще назови как в gcc...
Yandex
Объявления
25.11.2011, 14:35     Шаблонный класс List
Ответ Создать тему
Опции темы

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