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

Переопределение операции присваивания - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.60
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 04:21     Переопределение операции присваивания #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
30
31
32
33
#ifndef cd_h
#define cd_h
 
class Cd
{
private:
    char* performance;
    char* label;
    int selections;
    double playtime;
public:
    Cd();
    Cd(const char* s1, const char* s2, int n, double x);
    Cd(const Cd& c);
    virtual Cd& operator=(const Cd& c);
    virtual ~Cd();
    virtual void Report() const;
};
 
class Classic : public Cd
{
private:
    char* main_cmps;
public:
    Classic();
    Classic(const char* mc, const char* s1, const char* s2, int n, double x);
    Classic(char* mc, const Cd& c);
    Classic(const Classic& c);
    virtual Classic& operator=(const Cd& c);
    virtual ~Classic();
    virtual void Report() const;
};
#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
#include "cd.h"
#include <iostream>
 
//class Cd
Cd::Cd()
{
    performance = label = nullptr;
    selections = playtime = 0;
}
 
Cd::Cd(const char* s1, const char* s2, int n, double x)
{
    performance = new char[strlen(s1) + 1];
    strcpy(performance, s1);
    label = new char[strlen(s2) + 1];
    strcpy(label, s2);
    selections = n;
    playtime = x;
}
 
Cd::Cd(const Cd& c)
{
    performance = new char[strlen(c.performance) + 1];
    strcpy(performance, c.performance);
    label = new char[strlen(c.label) + 1];
    strcpy(label, c.label);
    selections = c.selections;
    playtime = c.playtime;
}
 
Cd& Cd::operator=(const Cd& c)
{
    performance = new char[strlen(c.performance) + 1];
    strcpy(performance, c.performance);
    label = new char[strlen(c.label) + 1];
    strcpy(label, c.label);
    selections = c.selections;
    playtime = c.playtime;
    return *this;
}
 
Cd::~Cd()
{
    delete[] performance;
    delete[] label;
}
 
void Cd::Report() const
{
    std::cout << "Performance: " << performance << "\t" << "Label: " << label << std::endl
        << "Selections: " << selections << "\t" << "Playtime: " << playtime << std::endl;
}
 
 
// Class Classic
Classic::Classic() :Cd()
{
    main_cmps = nullptr;
}
 
Classic::Classic(const char* mc, const char* s1, const char* s2, int n, double x) :Cd(s1, s2, n, x)
{
    main_cmps = new char[strlen(mc) + 1];
    strcpy(main_cmps, mc);
}
 
Classic::Classic(char* mc, const Cd& c) : Cd(c)
{
    main_cmps = new char[strlen(mc) + 1];
    strcpy(main_cmps, mc);
}
 
Classic::Classic(const Classic& c):Cd(c)
{
    main_cmps = new char[strlen(c.main_cmps) + 1];
    strcpy(main_cmps, c.main_cmps);
}
 
Classic& Classic::operator=(const Cd& c)
{
    if (this == &c)
        return *this;
    Classic temp = (const Classic&)c;
    Cd::operator=(c);
    main_cmps = new char[strlen(temp.main_cmps) + 1];
    strcpy(main_cmps, temp.main_cmps);
    return *this;
}
 
Classic::~Classic()
{
    delete[] main_cmps;
    
}
 
void Classic::Report() const
{
    Cd::Report();
    std::cout << "Main composition: " << main_cmps << std::endl;
}
Почему то вызвается метод базового класа при присваивании межу собой обьектов производного класса.
Заранее спасибо.

Добавлено через 7 минут
Вследствие чего выводистя окно с ошибкой, как я понимаю из за того, что деструктор пытается удалить несуществующий блок памяти.
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
MrCold
851 / 749 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
29.07.2014, 05:42     Переопределение операции присваивания #2
На каждый оператор New должен быть оператор Delete.
Не освобождаете память. Остальное не смотрел.
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 05:44     Переопределение операции присваивания #3
при присваивании одного объекта другому, сначала нужно очистить память, которая уже была выделена, а потом уже выделять новую, равную размеру присваемого объекта. Так-же перед всем этим следует проверить, не является ли аргумент тем-же самым объектом, если да, то и выделять ничего не нужно
C++
1
2
if (this == &c)
   return *this;
Судя по коду, ты делаешь упражнение из учебника Стивена Прата) посмотри предыдущие примеры по этой главе и сам всё поймёшь.
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 06:25  [ТС]     Переопределение операции присваивания #4
Цитата Сообщение от MrCold Посмотреть сообщение
На каждый оператор New должен быть оператор Delete.
Не освобождаете память. Остальное не смотрел.
В Деструкторе присутствуют все delete-ы. Память сдесь даже переосвобождается, из за чего и проблема.

Цитата Сообщение от dalay_lama Посмотреть сообщение
при присваивании одного объекта другому, сначала нужно очистить память, которая уже была выделена, а потом уже выделять новую, равную размеру присваемого объекта. Так-же перед всем этим следует проверить, не является ли аргумент тем-же самым объектом, если да, то и выделять ничего не нужно
Да, удаление предыдущего содержимого забыл, но пробелма не решилась т.к. присваивал и так пустому обьекту. Дело в том что Прата не писал о переопределении операции присваения. В примерах у него просто определены разные операции присваения для базового и производных классов. Может это и не может понадобится, но мне стало интересно и захотелось попробовать написать следующий код:
C++
1
2
3
4
5
    Cd obj1;  // базовый класс
    Classic obj2; //производный класс
    Cd* ptr = &obj1; 
    *ptr = obj2;  
    ptr->Report();  // ну и вот здесь хотелось бы что бы использовался метод производного класса
Но выходит так, что после этого, что даже простые обьекты производного класса при присвоении межу собой вызывают операцию присваения, которая определена в базовом класе, а не в производном. Не знаю что не так сделал.
MrCold
851 / 749 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
29.07.2014, 06:34     Переопределение операции присваивания #5
Цитата Сообщение от Gwini Посмотреть сообщение
В Деструкторе присутствуют
деструкторы здесь не помогут.
Но dalay_lama уже сказал что и как
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 06:42     Переопределение операции присваивания #6
Цитата Сообщение от Gwini Посмотреть сообщение
Дело в том что Прата не писал о переопределении операции присваения. В примерах у него просто определены разные операции присваения для базового и производных классов.
Вот ты бестыжий врёшь и не краснеешь

Как дома буду, обязательно ткну носом в эти листинги и то, где он описывал проблемы, когда выделяешь память из кучи в конструкторе

а пока, перечитай главу ещё раз и повнимательней глядишь и сам найдёшь то, что я тебе выше писал
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 06:46  [ТС]     Переопределение операции присваивания #7
Цитата Сообщение от MrCold Посмотреть сообщение
Но dalay_lama уже сказал что и как
не помогло

Добавлено через 3 минуты
Цитата Сообщение от dalay_lama Посмотреть сообщение
когда выделяешь память из кучи в конструкторе
да читал я глубокое копирование и тд. Все работает, если убрать это присвоение триклятое...Его в самом задание то нет, но оно мне спать не дает спокойно
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.07.2014, 06:47     Переопределение операции присваивания #8
Цитата Сообщение от Gwini Посмотреть сообщение
как я понимаю из за того, что деструктор пытается удалить несуществующий блок памяти.
Из-за того, что указатели нулевые, а к ним применяется strlen().
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 06:56     Переопределение операции присваивания #9
И кстати, только сейчас обратил внимание. Очень ты не внимательно читаешь) Если б внимательно читал, то знал бы, что операция присваивания не наследуется, соответственно, виртуальной её не нужно объявлять. Если операция присваивания по умолчанию не переопределена, то свойства просто почленно друг друга скопируют, а если класс является производным, тогда сначала вызовется оператор присваивания базового класса, чтобы скушать свои свойства( и соответственно для него, вызовется тот оператор присваивания который определён, т.е. который написал ты или по умолчанию). Соответственно, если ты переопределяешь для производного класса оператор присваивания, тебе нужно вызвать самому оператор присваивания для базового класса
C++
1
BaseClass::operator=(argument);//вызов оператора присваивания для базового класса
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 06:57  [ТС]     Переопределение операции присваивания #10
Цитата Сообщение от alsav22 Посмотреть сообщение
Из-за того, что указатели нулевые, а к ним применяется strlen().
Да вроде нормально... strlen применяется только в конструкторах к указателям на строки.
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 07:02     Переопределение операции присваивания #11
Выложи, что у тебя в итоге сейчас получается
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 07:14  [ТС]     Переопределение операции присваивания #12
Цитата Сообщение от dalay_lama Посмотреть сообщение
И кстати, только сейчас обратил внимание. Очень ты не внимательно читаешь) Если б внимательно читал, то знал бы, что операция присваивания не наследуется, соответственно, виртуальной её не нужно объявлять. Если операция присваивания по умолчанию не переопределена, то свойства просто почленно друг друга скопируют, а если класс является производным, тогда сначала вызовется оператор присваивания базового класса, чтобы скушать свои свойства( и соответственно для него, вызовется тот оператор присваивания который определён, т.е. который написал ты или по умолчанию). Соответственно, если ты переопределяешь для производного класса оператор присваивания, тебе нужно вызвать самому оператор присваивания для базового класса
Есть там такое
C++
1
2
3
4
5
6
7
8
9
10
11
12
Classic& Classic::operator=(const Cd& c)
{
 
    if (this == &c)
        return *this;
    delete[] main_cmps;
    Classic temp = (const Classic&)c;   
Cd::operator=(c);
    main_cmps = new char[strlen(temp.main_cmps) + 1];
    strcpy(main_cmps, temp.main_cmps);
    return *this;
}
И я читал внимательно читал что не наследуется, но вирутальной ее сделать можно. Я понимаю что это может и бесполезно, но мне все же интересно.

Добавлено через 11 минут
Вот к примеру, где могла бы использоватся переопределенная операция присваивания
C++
1
2
3
4
    Cd* ptr = &c1; //указатель на базовый класс, с1 обьект базового класса
    ptr->Report();
    *ptr = c3;    //с3 - обьект производного класса
    ptr->Report();
Может это вообще не имеет смысла?
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 07:22     Переопределение операции присваивания #13
Цитата Сообщение от Gwini Посмотреть сообщение
Может это вообще не имеет смысла?
Имеет.
Выложи весь код. Покажи, что поменял от старта топика

Добавлено через 3 минуты
стоооооп)
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 07:24  [ТС]     Переопределение операции присваивания #14
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
#ifndef cd_h
#define cd_h
 
class Cd
{
private:
    char* performance;
    char* label;
    int selections;
    double playtime;
public:
    Cd();
    Cd(const char* s1, const char* s2, int n, double x);
    Cd(const Cd& c);
    virtual Cd& operator=(const Cd& c);
    virtual ~Cd();
    virtual void Report() const;
};
 
class Classic : public Cd
{
private:
    char* main_cmps;
public:
    Classic();
    Classic(const char* mc, const char* s1, const char* s2, int n, double x);
    Classic(char* mc, const Cd& c);
    Classic(const Classic& c);
    virtual Classic& operator=(const Cd& c);
    virtual ~Classic();
    virtual void Report() const;
};
#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
#include "cd.h"
#include <iostream>
 
//class Cd
Cd::Cd()
{
    performance = label = nullptr;
    selections = playtime = 0;
}
 
Cd::Cd(const char* s1, const char* s2, int n, double x)
{
    performance = new char[strlen(s1) + 1];
    strcpy(performance, s1);
    label = new char[strlen(s2) + 1];
    strcpy(label, s2);
    selections = n;
    playtime = x;
}
 
Cd::Cd(const Cd& c)
{
    performance = new char[strlen(c.performance) + 1];
    strcpy(performance, c.performance);
    label = new char[strlen(c.label) + 1];
    strcpy(label, c.label);
    selections = c.selections;
    playtime = c.playtime;
}
 
Cd& Cd::operator=(const Cd& c)
{
    std::cout << "\n===base\n";
    delete[] performance;
    delete[] label;
    performance = new char[strlen(c.performance) + 1];
    strcpy(performance, c.performance);
    label = new char[strlen(c.label) + 1];
    strcpy(label, c.label);
    selections = c.selections;
    playtime = c.playtime;
    return *this;
}
 
Cd::~Cd()
{
    delete[] performance;
    delete[] label;
}
 
void Cd::Report() const
{
    std::cout << "\nPerformance: " << performance << "\t" << "Label: " << label << std::endl
        << "Selections: " << selections << "\t" << "Playtime: " << playtime << std::endl;
}
 
 
// Class Classic
Classic::Classic() :Cd()
{
    main_cmps = nullptr;
}
 
Classic::Classic(const char* mc, const char* s1, const char* s2, int n, double x) :Cd(s1, s2, n, x)
{
    main_cmps = new char[strlen(mc) + 1];
    strcpy(main_cmps, mc);
}
 
Classic::Classic(char* mc, const Cd& c) : Cd(c)
{
    main_cmps = new char[strlen(mc) + 1];
    strcpy(main_cmps, mc);
}
 
Classic::Classic(const Classic& c):Cd(c)
{
    main_cmps = new char[strlen(c.main_cmps) + 1];
    strcpy(main_cmps, c.main_cmps);
}
 
Classic& Classic::operator=(const Cd& c)
{
    std::cout << "\n===der\n";
    if (this == &c)
        return *this;
    Cd::operator=(c);
    delete[] main_cmps;
    Classic temp = (const Classic&)c;   
    main_cmps = new char[strlen(temp.main_cmps) + 1];
    strcpy(main_cmps, temp.main_cmps);
    return *this;
}
 
Classic::~Classic()
{
    delete[] main_cmps;
}
 
void Classic::Report() const
{
    Cd::Report();
    std::cout << "Main composition: " << main_cmps << std::endl;
}
Использование класса:
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
#include <iostream>
#include "cd.h"
using namespace std;
 
void Bravo(const Cd& d);
int main()
{
    Cd c1("Beatles", "Capitol", 14, 35.5);
    Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
    Cd* pcd = &c1;
    cout << "\nUsing type cd* pointer to object:\n";
    pcd->Report();
    pcd = &c2;  
    pcd->Report();
    cout << "\nCalling a function with Cd reference argument:\n";
    Bravo(c1);
    Bravo(c2);
    cout << "\nTesting assignment: ";
    Classic copy;
    copy = c2;     // здесь вместо присваения производного класа, вызывается присваение базового
    copy.Report();
    Classic c3("la-la-la-la", c1);
    c3.Report();
    Classic c4 = c3;
    c4.Report();
 
    Cd* ptr = &c1;   //указатель на базовый класс, с1 обьект базового класса
    ptr->Report();   //вызвается метод базового класса
    *ptr = c3;      //с3 — обьект производного класса
    ptr->Report();   //тут надо бы, что б вызывался метод производного класса
 
 
    return 0;
}
 
void Bravo(const Cd& disk)
{
    disk.Report();
}
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 07:31     Переопределение операции присваивания #15
стоооооп) теперь я понял)
смотри.
C++
1
2
3
4
Cd* ptr = &c1; //указатель на базовый класс, с1 обьект базового класса - ОК
ptr->Report();//вывоз метода базового класса
*ptr = c3;//с3 у нас является производным классом. ты выполняешь операцию присваивания для БАЗОВОГО класса
ptr->Report();
К чему я это, ты же не меняешь адрес, на который указывает ptr. Ты ему сказал, получи адрес c1 - он его получил. Потом ты ему говоришь, чтобы он принял значения от c3. По сути, всё равно что вот так вот написать:
C++
1
2
Cd c1;
c1 = c3;
Вызовется операция присваивания БАЗОВОГО класса, т.к. мы помним, что ссылки на базовый класс, могу принимать и на производные классы. Соответственно, базовый класс получит базовые значения из производного.
отсюда и получается, что ptr->Report(); вызывает у тебя метод базового класса, потому-что он и хранит адрес объекта базового класса!
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 07:37  [ТС]     Переопределение операции присваивания #16
Цитата Сообщение от dalay_lama Посмотреть сообщение
стоооооп) теперь я понял)
смотри.
Код C++
1
2
3
4
Cd* ptr = &c1; //указатель на базовый класс, с1 обьект базового класса - ОК
ptr->Report();//вывоз метода базового класса
*ptr = c3;//с3 у нас является производным классом. ты выполняешь операцию присваивания для БАЗОВОГО класса
ptr->Report();
К чему я это, ты же не меняешь адрес, на который указывает ptr. Ты ему сказал, получи адрес c1 - он его получил. Потом ты ему говоришь, чтобы он принял значения от c3. По сути, всё равно что вот так вот написать:
Код C++
1
2
Cd c1;
c1 = c3;
Вызовется операция присваивания БАЗОВОГО класса, т.к. мы помним, что ссылки на базовый класс, могу принимать и на производные классы. Соответственно, базовый класс получит базовые значения из производного.
отсюда и получается, что ptr->Report(); вызывает у тебя метод базового класса, потому-что он и хранит адрес объекта базового класса!
Понятно, значит это смысла не имеет и впринципе переопределять операцию присваения не нужно. Но мне все же интересно это:
C++
1
2
3
Classic copy;
    copy = c2;     // здесь вместо присваения производного класа, вызывается присваение базового
    copy.Report();
Кстати ошибка вылитает именно здесь, а именно из за того что деструктор производного класа пытается удалить член char* main_cmps, память под которого не была выделена т.к. вызывается присваение базового а не производного класса.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.07.2014, 07:52     Переопределение операции присваивания #17
Цитата Сообщение от Gwini Посмотреть сообщение
Да вроде нормально... strlen применяется только в конструкторах к указателям на строки.
Это конструктор?
Цитата Сообщение от Gwini Посмотреть сообщение
Cd& Cd::operator=(const Cd& c)
{
* * performance = new char[strlen(c.performance) + 1];
* * strcpy(performance, c.performance);
* * label = new char[strlen(c.label) + 1];
* * strcpy(label, c.label);
* * selections = c.selections;
* * playtime = c.playtime;
* * return *this;
}
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 07:54     Переопределение операции присваивания #18
Цитата Сообщение от Gwini Посмотреть сообщение
Понятно, значит это смысла не имеет и впринципе переопределять операцию присваения не нужно.
В базовом классе, для производного класса определять операцию присвоения нет необходимости. Только может, если ты хочешь знать, что принял именно производный класс и в соответствии с этим сделать, что-то ещё, но, к сожалению, никакого примера придумать не могу

Цитата Сообщение от Gwini Посмотреть сообщение
Кстати ошибка вылитает именно здесь, а именно из за того что деструктор производного класа пытается удалить член char* main_cmps, память под которого не была выделена т.к. вызывается присваение базового а не производного класса
я рад, что ты разобрался
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 08:01  [ТС]     Переопределение операции присваивания #19
Цитата Сообщение от alsav22 Посмотреть сообщение
Это конструктор?
Нет, но strlen все равно применяется к строке в уже существующему объекту.

Добавлено через 6 минут
Цитата Сообщение от dalay_lama Посмотреть сообщение
я рад, что ты разобрался
Спасибо знать бы еще почему вызвается присвоение базового класса вместо производного Ну да ладно, если перопределние присвоения бесполезно то может и незачем знать. Просто определю не виртуальное присвоение в производном класе и все. Еще раз спасибо.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.07.2014, 08:12     Переопределение операции присваивания
Еще ссылки по теме:

Для чего нужно переопределение оператора присваивания? C++
C++ Переопределение операции []
C++ Переопределение операции вычитания строк

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

Или воспользуйтесь поиском по форуму:
dalay_lama
 Аватар для dalay_lama
65 / 65 / 7
Регистрация: 22.09.2012
Сообщений: 434
29.07.2014, 08:12     Переопределение операции присваивания #20
Я немного не понял, почему ты не понял=)
давай ещё раз:
C++
1
2
3
4
5
6
Cd ob1;//хей, я объект, базового класса
Classic ob2;//хей, я объект производного класса
 
ob1 = ob2;/*присваиваем объекту базового класса, значения производного. Почему так можно? потому-что прототип operator(Cd &cd) - аргумент ссылочка на базовый, да? а объекты производного класса, можно передавать по ссылке объектам базового*/
ob2 = ob1;/*а такое уже не прокатит, обратное нельзя, ссылки на производный, не могут принимать ссылки на базовый(только если не делать приведение типа), соответственно, для такого вида нужно написать своё присвоение с блэк джеком и плюшками.
прототип такой Classic::operator=(Cd &cd);*/
что именно не понятно?
Yandex
Объявления
29.07.2014, 08:12     Переопределение операции присваивания
Ответ Создать тему
Опции темы

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