Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/4: Рейтинг темы: голосов - 4, средняя оценка - 4.50
29 / 24 / 5
Регистрация: 15.10.2019
Сообщений: 268
1

оператор присвоение и конструктор копии

08.10.2022, 17:08. Показов 702. Ответов 9
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
класс Object родительский, в нем массив, который хранит информацию какие операции совершались с объектами класса. Так же в нем должны быть конструктор копирования и оператор присвоения. Ну и от этого класса наследуются класс Complex, который описывает комплексные числа и позволяет производить операции над ними.

так вот, сделал в классе Object и конструктор копии и оператор присваивания. И гдет накосячил. Потому что когда я пишу
C++ (Qt)
1
Complex myC = myA + myB;
я ожидаю, что будет запущен мой конструктор копии, но он не запускается.

зато когда пишу
C++ (Qt)
1
myC = myA + myB;
то я по отладочным печатям вижу, что сначала запускается оператор присваиванья, а затем конструктор копирования. вместо просто использования оператора присвоения.

так же, в object, через статические параметры я веду подсчет кол-ва созданный объектов, и каждому объекту присваиваю ID. В моем понимание, когда работает конструктор копирования, то кол-во объектов должно увеличиваться. А когда оператор присвоения работает, то кол-во объектов то же, т.к. мы уже созданному ранне объекту присваеваем значения другого объекта. Но у меня тут вобще каша. Получается что при работе оператора присвоения кол-во созданных ув +2.

C++ (Qt)
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#include <iostream>
#include <math.h> 
#include <time.h>
#include <stdlib.h>
using namespace std;
 
enum OperationView {PLUS, MINUS};
const char* OperationViewName[] = {"сложение", "вычитание"};
 
 
class Object
{
    static int nextId; // следующий присваиваемый номер
    static int curAlive; //текущее кол-во экземпляров данного класса
    int id;
    int curEl;
    int curSize;
    char** arr;
    
public:
    Object() 
    {
        id = nextId++;
        ++curAlive;
        curSize = 10;
        arr = new char*[curSize];
        for(int i = 0; i < curSize; ++i)
            arr[i] = (char *) "";
        curEl = 0;
    }
    
    Object(const Object& otherObj) 
    {
        cout<<endl<<"copy ctor!"<<endl;
        id = nextId++;
        ++curAlive;
        curSize = otherObj.curSize;
        arr = new char*[curSize];
        for(int i = 0; i < curSize; ++i)
            arr[i] = otherObj.arr[i];
        curEl = otherObj.curEl;
    }
    
    ~Object() 
    {
        --curAlive;
        delete[] arr;
    }
    
    Object operator= (const Object& otherObj)
{
    cout<<endl<<"oper prisvo!"<<endl;
    this->clearOp();
    curSize = otherObj.curSize;
        arr = new char*[curSize];
        for(int i = 0; i < curSize; ++i)
            arr[i] = otherObj.arr[i];
        curEl = otherObj.curEl;
    return *this;
}
    
    void addOp(OperationView a)
    {
        if (curEl == curSize)
        {
            int newSize;
            newSize = curSize + 10;
            //curSize *= 2;
            char** tmpArr = new char*[newSize];
            for(int i = 0; i < newSize; ++i)
            {
                if (i <= curSize)
                {
                    tmpArr[i] = arr[i];
                }
                else
                {
                    tmpArr[i] = (char *) "";
                }
            }
            delete[] arr;
            arr = tmpArr;
            curSize = newSize;
        }
        arr[curEl] = (char *) OperationViewName[a];
        curEl++;
    }
    
    void clearOp()
    {
        delete[] arr;
        curSize = 10;
        arr = new char*[curSize];
        for(int i = 0; i < curSize; ++i)
            arr[i] = (char *) "";
        curEl = 0;
    }
    
    void printOp()
    {   
        if (arr[0] != "")
        {
            cout << "Для объекта № " << id << " выполнены следующие действия:" << endl;
            for(int i = 0; i < curSize; ++i)
            cout << arr[i] << " ";
        }
        else
        {
            cout << "С объектом № " << id << " не выполнялись операции." << endl;
        }
        cout << endl;
    }
    
    void print()
    {
        cout << "Объект №" << id << endl;
    }
    
    //статический метод выводит информацию по кол-ву объектов класса
    static void printTotalInfo()
    {
        cout << "Было создано " << nextId - 1 << " объектов. Сейчас активно:" << curAlive << endl;
    }
};
 
int Object::nextId = 1;
int Object::curAlive = 0;
 
 
class Complex : public Object
{
    float a, b;
    bool real;
 
public:
    
    Complex(float a, float b)
    {
        setA(a);
        setB(b);
        if (b == 0)
        {
            this->real = false;
        }
        else
        {
            this->real = true;
        }   
    }
    
    float getA()const { return a; }
    void setA(float a) { this->a = a; };
    float getB()const { return b; }
    void setB(float b)
    {
     this->b = b;
     if (b == 0)
        {
            this->real = false;
        }
        else
        {
            this->real = true;
        }   
     };
    bool getReal() { return real; }
    
    void invComplex()
    {
        this->b = -b;
    }
    
    
    void revComplex()
    {
        float oldA = this->a;
        this->a = this->a / ((this->a * this->a) + (this->b * this->b));
        this->b = float(((-1 * this->b)) / ((oldA * oldA) + (this->b * this->b)));
    }
    
    
    void printAbout()
    {
        char sign;
    if (b < 0)
    {
        sign = '-';
    }
    else
    {
        sign = '+' ;
    }
    cout << "(" << a << " " << sign << " " << fabs(b) << " * i) ";
    if (real)
    {
        cout << "[complex number]" << endl; 
    }
    else
    {
        cout << "[real number]" << endl;    
    }
    }   
 
    static Complex randomNum(float& a, float& b)
    {
        srand(time(NULL));
        if (a > b)
        {
            float c;
            c = b;
            b = a;
            a = c;  
        }
        float c = (float) rand() / RAND_MAX * (b - a) + a;
        float d = (float) rand() / RAND_MAX * (b - a) + a;
        cout << "чек" << endl;
        return Complex {c, d};
    }
 
};
 
 
Complex operator+ (Complex& a, Complex& b)
{
    a.addOp(PLUS);
    b.addOp(PLUS);
    return Complex { b.getA() + a.getA(), b.getB() + a.getB() };
}
 
Complex operator- (Complex& a, Complex& b)
{
    a.addOp(MINUS);
    b.addOp(MINUS);
    return Complex { a.getA() - b.getA(), a.getB() - b.getB() };
}
 
Complex operator* (const Complex& a, const Complex& b)
{
    return Complex { (a.getA() * b.getA()) - (a.getB() * b.getB()), (a.getA() * b.getB()) + (b.getA() * a.getB()) };
}
 
Complex operator/ (const Complex& a, const Complex& b)
{
    return Complex { ((a.getA() * b.getA()) + (a.getB() * b.getB())) / ((b.getA() * b.getA()) + (b.getB() * b.getB())), ((b.getA() * a.getB()) - (a.getA() * b.getB())) / ((b.getA() * b.getA()) + (b.getB() * b.getB())) };
}
 
 
 
 
 
int main()
{
    system("chcp 1251");
    Complex myA(1, 1);
    Complex myB(-2, -1);
    myA.printAbout();
    myB.printAbout();
    Complex myC = myA + myB;
    myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA - myB;
    //myC = myA + myB;
    //myC = myA + myB;
    //myC = myA + myB;
    myC.printAbout();
    myC.print();
    cout << endl;
    //Object a, v, c;
    //Object::printTotalInfo();
    Complex::printTotalInfo();
    
    //Complex:printOp(myA);
    //myA.addOp(1);
    myA.printOp();
    myB.printOp();
    myC.printOp();
    
    Complex myZ = myA;
    myC = myA + myB;
    myA.printAbout();
    myA.printOp();
    myA.print();
    myZ.printAbout();
    myZ.printOp();
    myZ.print();
    float a, b;
    a = -100; b = 100;
    //cin >> a;
    //cin >> b;
    Complex myD = Complex::randomNum(a, b);
     myD.printAbout();  myD.print();
    return 0;
}
Добавлено через 1 час 20 минут
При чем,
C++ (Qt)
1
2
Complex myC(3, 3);
    Complex myJ = myC;
вот так вызывается как я и хотел конструктор копирования

может ли быть проблема где нибудь в моих перегруженных операторах для класса Complex?

Добавлено через 47 минут
возможно, из за того что оператор присвоения ждет что ему будут давать объект Комплекс
C++ (Qt)
1
myC = myA + myB;
, то он сумму myA + myB заносит во временно созданный объект, но при этом в перегруженном операторе + тоже при возврате используется временный объект.

Добавлено через 7 минут
но все равно не понимаю почему
C++ (Qt)
1
Complex myJ = myA + myB;
используется стандартный конструктор, без оператора присвоения и без конструктора копирования
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.10.2022, 17:08
Ответы с готовыми решениями:

Почему когда возвращается об'єкт создается новая копия но она создается через конструктор а не через конструктор копии?
Я создал конструктор копий чтоб он визивался при созданию копий функция возвращает обьект но когда...

Конструктор копии
Конструктор копии вызывается при: 1)явном создании копии 2)при передачи параметров в функцию (по...

конструктор копии
Мне кажется что здесь также должен вызывать конструктор копия при возврате объекта obj из функции...

Конструктор копии
Здравствуйте! Не могу никак правильно использовать конструктор копии, тоесть создать копию обьекта...

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

9
4866 / 2664 / 914
Регистрация: 29.11.2010
Сообщений: 5,747
08.10.2022, 18:05 2
Это называется copy elision и регламентируется в стандарте.

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.
В некоторых случаях компилятор может опускать вызов конструкторов даже если те имеют побочные эффекты.

В частности в вашем случае:
in a return statement in a function with a class return type, when the expression is the name of a non-volatile object with automatic storage duration (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the object directly into the function call's return object
Вольная трактовка для частного случая: если вы возвращаете из функции новосозданный объект, который потом присвоится переменной того же типа, компилятор может пропустить конструктор копирования.

Добавлено через 1 минуту
В референсах к языку можно найти более подробное описание этого процесса.

Где поведение описывается несколько более жоское:
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:
Компилятор ОБЯЗАН пропустить копирование и перемещение, даже если копирование перемещение имеет явные побочные эффекты.
0
29 / 24 / 5
Регистрация: 15.10.2019
Сообщений: 268
08.10.2022, 18:09  [ТС] 3
lemegeton, получается, что это как бы нормально все? А то у меня все равно огромные сомнения в правильности моего кода
0
4866 / 2664 / 914
Регистрация: 29.11.2010
Сообщений: 5,747
08.10.2022, 18:56 4
Лучший ответ Сообщение было отмечено billy121 как решение

Решение

Цитата Сообщение от billy121 Посмотреть сообщение
получается, что это как бы нормально все?
Поведение, когда в случае
Цитата Сообщение от billy121 Посмотреть сообщение
Complex myJ = myA + myB;
Не вызываются конструкторы копирования -- стандартное.

Добавлено через 47 секунд
Цитата Сообщение от billy121 Посмотреть сообщение
А то у меня все равно огромные сомнения в правильности моего кода
Пожалуй, логика ваших конструкторов не учитывает такое поведение.
1
29 / 24 / 5
Регистрация: 15.10.2019
Сообщений: 268
08.10.2022, 19:01  [ТС] 5
lemegeton, Ваш ответ звучит очень воодушевляющим. А то я уже просидел прилично часов с данным вопросом, гугля и пытаясь разобраться. Спасибо Вам!
0
4866 / 2664 / 914
Регистрация: 29.11.2010
Сообщений: 5,747
08.10.2022, 19:05 6
Цитата Сообщение от billy121 Посмотреть сообщение
Спасибо Вам!
Пожалуйста. Обращайтесь. )
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
08.10.2022, 19:24 7
Цитата Сообщение от billy121 Посмотреть сообщение
Object operator= (const Object& otherObj)
Не совсем корректен этот момент. По стандартной семантике оператор присваивания должен вернуть ссылку, а у вас он возвращает объект.

Цитата Сообщение от billy121 Посмотреть сообщение
В моем понимание, когда работает конструктор копирования, то кол-во объектов должно увеличиваться. А когда оператор присвоения работает, то кол-во объектов то же, т.к. мы уже созданному ранне объекту присваеваем значения другого объекта. Но у меня тут вобще каша. Получается что при работе оператора присвоения кол-во созданных ув +2.
Собственно это скорее всего и является причиной описанных вами в этой цитате явлений.
1
29 / 24 / 5
Регистрация: 15.10.2019
Сообщений: 268
08.10.2022, 19:33  [ТС] 8
DrOffset, типо нужно вернуть просто this, а не *this?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
08.10.2022, 19:35 9
Лучший ответ Сообщение было отмечено billy121 как решение

Решение

Цитата Сообщение от billy121 Посмотреть сообщение
типо нужно вернуть просто this, а не *this?
Нет...

У вас написано:
C++
1
Object operator= (const Object& otherObj)
А должно быть
C++
1
Object& operator= (const Object& otherObj)
1
29 / 24 / 5
Регистрация: 15.10.2019
Сообщений: 268
08.10.2022, 21:54  [ТС] 10
DrOffset, хорошо, я позже попробую. Спасибо за совет!

Добавлено через 2 часа 15 минут
DrOffset, ты просто лучший! во всей этой моей писанине нашел ошибку! Все исправил, все заработало, как должно было))) Спасибо тебе, ЧЕЛОВЕЧИЩЕ!!!
0
08.10.2022, 21:54
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.10.2022, 21:54
Помогаю со студенческими работами здесь

Конструктор копии и операторы
list::list(list const&amp; l) { l.H(); if (l.head==NULL) {head=present=NULL; return;}...

Конструктор копии в Классах
Подскажите пожалуйста правильно ли я написала и вызвала конструктор копии и деструктор, а то мне...

Не вызывается конструктор копии
#define st system(&quot;pause&quot;); #include &lt;iostream&gt; #include &lt;string.h&gt; using namespace std; class...

Для шаблонного класса перегрузить оператор присваивания, copy-конструктор, объекты cin и cout, оператор *
Помогите в следующем: Для класса шаблона следует перегрузить оператор присваивания, конструктор...

Приоритетная очередь и конструктор копии
День добрый, форумчане! Прошу просвятить в таком вопрос: -имеется класс, и в мейне пытаюсь...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Как запретить подсветку выделенного текста с помощью CSS
InfoMaster 20.01.2025
Подсветка текста при выделении является стандартным поведением браузера, которое не всегда соответствует дизайнерским решениям или функциональным требованиям веб-приложения. Выделение текста может. . .
Как выполнить другую программу или системную команду из Python
InfoMaster 20.01.2025
Python предоставляет мощные инструменты для выполнения системных команд и управления внешними процессами, что делает его идеальным выбором для автоматизации различных задач системного. . .
Как узнать директорию bash-скрипта из самого bash-скрипта
InfoMaster 20.01.2025
При разработке bash-скриптов одной из важных задач является определение директории, в которой находится исполняемый скрипт. Это критически важно для корректной работы с файлами, загрузки конфигураций. . .
В чем разница между let и var в JavaScript
InfoMaster 20.01.2025
JavaScript прошел длинный путь эволюции с момента своего создания в 1995 году. Одним из важнейших аспектов развития языка стало совершенствование механизмов объявления и управления переменными. . . .
Эффективная работа со строками в Go
InfoMaster 20.01.2025
Язык программирования Go предлагает уникальный подход к работе со строками, который существенно отличается от многих других языков программирования. В Go строки представляют собой неизменяемые. . .
Как проверить, что отображение (map) содержит ключ в Go
InfoMaster 20.01.2025
Отображения (maps) в языке программирования Go представляют собой мощные структуры данных, которые позволяют хранить пары ключ-значение и обеспечивают быстрый доступ к данным по уникальным. . .
Как организовать домашнее хранилище фильмов с общим доступом для всей семьи
InfoMaster 20.01.2025
Преимущества домашнего медиасервера В современном мире, где цифровой контент стал неотъемлемой частью нашей жизни, организация домашнего медиасервера становится все более актуальной задачей. . . .
Перспективы развития жестких дисков: есть ли у них будущее?
InfoMaster 20.01.2025
История и эволюция жестких дисков История развития жестких дисков начинается в 1956 году, когда компания IBM представила первое устройство для хранения данных на магнитных пластинах - IBM 350. . .
Распознавание изображений (компьютерное зрение) на C++
InfoMaster 20.01.2025
Введение в компьютерное зрение и основы работы с изображениями Компьютерное зрение представляет собой одну из наиболее динамично развивающихся областей информационных технологий, позволяющую. . .
Какой язык программировани­я лучший для разработки нейронных сетей
InfoMaster 20.01.2025
В современном мире технологий искусственные нейронные сети становятся неотъемлемой частью множества инновационных решений, от распознавания речи до автоматического управления транспортными. . .
Как подключить JavaScript файл в другом JavaScript файле
InfoMaster 20.01.2025
В современной веб-разработке организация кодовой базы играет ключевую роль в создании масштабируемых и поддерживаемых приложений. Модульность и правильное структурирование кода стали неотъемлемыми. . .
Как откатить изменения в исходниках, не внесенные в Git
InfoMaster 20.01.2025
При работе с системой контроля версий Git разработчики часто сталкиваются с необходимостью отменить внесенные изменения в исходном коде. Особенно актуальной становится ситуация, когда изменения еще. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru