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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 33, средняя оценка - 4.67
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
#1

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

17.11.2011, 23:21. Просмотров 4551. Ответов 22
Метки нет (Все метки)

Имеется 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;
}
Без шаблонов все работало.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.11.2011, 23:21     Шаблонный класс List
Посмотрите здесь:

Шаблонный класс list - C++
Доброго времени суток, пишу шаблонный list, но вот на определённом этапе возникла ошибка: #ifndef LIST_H #define LIST_H ...

Шаблонный класс list, собственная реализация - C++
Привет всем. Я по чуть-чуть пишу шаблонный класс list с добавлением элементов в начало списка. Уже на свой страх и риск реализовал три...

Создать динамический шаблонный класс односвязный список - List - C++
помогите пожалуйста с задание в универ задали и я вот сижу парюсь! буду очень вам благодарен Создать динамический шаблонный класс...

Написать шаблонный класс List для работы с одноправленными списками в динамической памяти - C++
Для объектов класса List определить операции проверки списка на пустоту, добавления элемента в начало списка, в конец списка, подсчет...

Шаблонный класс - C++
Ребята, объясните пожалуйста, как работает шаблонный класс, своими словами, на скромном маленьком примерчике. Заранее благодарю.

Шаблонный класс - C++
Я запутался с шаблонами. Не пойму никак как вызвать конструктор с введенным в функции check_int() значением и как дальше вызвать функции...

Шаблонный класс - C++
День добрый. Пишу матричный калькулятор на шаблонном классе. Хочу добиться того, чтобы можно было оперировать с матрицами всех численных...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
lemegeton
2918 / 1347 / 134
Регистрация: 29.11.2010
Сообщений: 2,721
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,133
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
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
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
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++
Ребят, прошу Вашей помощи.. Программу я написала.. Она работает. Но теперь мне нужно переделать ее , используя шаблонный класс. Я...

шаблонный класс - C++
реализован согласно &quot;Создание конструкторов и деструктора&quot; на шаблон класса с параметром -Тип данных в файле, редактируется (байт / слово /...

Шаблонный класс - C++
#include &lt;iostream&gt; using namespace std; template &lt;class T&gt; class Vector{ private: int size, capacity; T* data; public: ...

Шаблонный класс - C++
Как его реализовать??? Смысл я понимаю, но вот как записать...не знаю:cry:

Шаблонный класс - C++
Подскажите как указать реализацию методов для шаблонного класса template &lt;class T_machine&gt; class hospital_room { ...


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

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

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