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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.60
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
#1

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

29.07.2014, 04:21. Просмотров 1402. Ответов 40
Метки нет (Все метки)

Есть вот такой класс:
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 минут
Вследствие чего выводистя окно с ошибкой, как я понимаю из за того, что деструктор пытается удалить несуществующий блок памяти.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.07.2014, 04:21
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Переопределение операции присваивания (C++):

Переопределение операции присваивания - C++
В случае, когда в классе есть члены, память под которые выделяется динамически, операцию присваивания, как и конструкторы с деструкторами...

Переопределение оператора присваивания - C++
Имеется такой простой класс: class TClass { private: float* A; int N; public: TClass(int _N) ...

Для чего нужно переопределение оператора присваивания? - C++
HumansClass&amp; operator=(const HumansClass&amp; right); //переопределение операции присваивания Для чего нужно переопределение оператора...

Операции присваивания - C++
Как можно проиллюстрировать возможности операций присваивания на примере программы?

Перегрузка операции присваивания и сложения - C++
Необходимо составить описание класса для определения одномерных массивов целых чисел. Границы индексов можно задавать произвольно, т.е....

Переопределение операции [] - C++
В классе строка переопределить операцию , которая будет возвращать символ по индексу, который передан в квадратные скобки. Помогите, не...

40
MrCold
855 / 753 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
29.07.2014, 05:42 #2
На каждый оператор New должен быть оператор Delete.
Не освобождаете память. Остальное не смотрел.
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
29.07.2014, 05:44 #3
при присваивании одного объекта другому, сначала нужно очистить память, которая уже была выделена, а потом уже выделять новую, равную размеру присваемого объекта. Так-же перед всем этим следует проверить, не является ли аргумент тем-же самым объектом, если да, то и выделять ничего не нужно
C++
1
2
if (this == &c)
   return *this;
Судя по коду, ты делаешь упражнение из учебника Стивена Прата) посмотри предыдущие примеры по этой главе и сам всё поймёшь.
1
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();  // ну и вот здесь хотелось бы что бы использовался метод производного класса
Но выходит так, что после этого, что даже простые обьекты производного класса при присвоении межу собой вызывают операцию присваения, которая определена в базовом класе, а не в производном. Не знаю что не так сделал.
0
MrCold
855 / 753 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
29.07.2014, 06:34 #5
Цитата Сообщение от Gwini Посмотреть сообщение
В Деструкторе присутствуют
деструкторы здесь не помогут.
Но dalay_lama уже сказал что и как
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
29.07.2014, 06:42 #6
Цитата Сообщение от Gwini Посмотреть сообщение
Дело в том что Прата не писал о переопределении операции присваения. В примерах у него просто определены разные операции присваения для базового и производных классов.
Вот ты бестыжий врёшь и не краснеешь

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

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

Добавлено через 3 минуты
Цитата Сообщение от dalay_lama Посмотреть сообщение
когда выделяешь память из кучи в конструкторе
да читал я глубокое копирование и тд. Все работает, если убрать это присвоение триклятое...Его в самом задание то нет, но оно мне спать не дает спокойно
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.07.2014, 06:47 #8
Цитата Сообщение от Gwini Посмотреть сообщение
как я понимаю из за того, что деструктор пытается удалить несуществующий блок памяти.
Из-за того, что указатели нулевые, а к ним применяется strlen().
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
29.07.2014, 06:56 #9
И кстати, только сейчас обратил внимание. Очень ты не внимательно читаешь) Если б внимательно читал, то знал бы, что операция присваивания не наследуется, соответственно, виртуальной её не нужно объявлять. Если операция присваивания по умолчанию не переопределена, то свойства просто почленно друг друга скопируют, а если класс является производным, тогда сначала вызовется оператор присваивания базового класса, чтобы скушать свои свойства( и соответственно для него, вызовется тот оператор присваивания который определён, т.е. который написал ты или по умолчанию). Соответственно, если ты переопределяешь для производного класса оператор присваивания, тебе нужно вызвать самому оператор присваивания для базового класса
C++
1
BaseClass::operator=(argument);//вызов оператора присваивания для базового класса
0
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
29.07.2014, 06:57  [ТС] #10
Цитата Сообщение от alsav22 Посмотреть сообщение
Из-за того, что указатели нулевые, а к ним применяется strlen().
Да вроде нормально... strlen применяется только в конструкторах к указателям на строки.
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
29.07.2014, 07:02 #11
Выложи, что у тебя в итоге сейчас получается
0
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();
Может это вообще не имеет смысла?
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
29.07.2014, 07:22 #13
Цитата Сообщение от Gwini Посмотреть сообщение
Может это вообще не имеет смысла?
Имеет.
Выложи весь код. Покажи, что поменял от старта топика

Добавлено через 3 минуты
стоооооп)
0
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();
}
0
dalay_lama
77 / 77 / 16
Регистрация: 22.09.2012
Сообщений: 480
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(); вызывает у тебя метод базового класса, потому-что он и хранит адрес объекта базового класса!
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.07.2014, 07:31
Привет! Вот еще темы с ответами:

Переопределение операции инкремента - C++
Добрый вечер! Задачка простая и кода с примерами в сети куча, но меня волнует вопрос почему компилятор ругается на мой код: Myclass...

Вызов функции с левой стороны от операции присваивания - C++
Здорова! Нужно перегрузить в классе String операцию выделения строки, но так чтобы она стояла слева от операции присваивания например...

Создаются ли копии объектов при операции присваивания? - C++
Доброго времени суток! Допустим есть объекты одного класса a1, a2, a3. Насколько я понимаю, при операции присваивания a1=a2 создаётся...

Переопределение операции вычитания строк - C++
Нужно переопределить операцию вычитания строк. То есть из первой строки вычитаются все символы,содержащиеся во второй строке. Я...


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

Или воспользуйтесь поиском по форуму:
15
Yandex
Объявления
29.07.2014, 07:31
Ответ Создать тему
Опции темы

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