1 / 1 / 1
Регистрация: 23.09.2014
Сообщений: 33
1

Объясните, зачем в коде нужен явный конструктор копирования

15.02.2016, 19:01. Показов 1460. Ответов 7
Метки нет (Все метки)

Добрый день, хочу понять код, почему тут обезательно надо явный конструктор копирования?

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
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
#include <iostream>
 
using namespace std;
 
class vector
{
private: // переменные в private так как это принцип инкапсуляции 
    // размерность
    int n;
    
    // сами значения
    double* v;
    
public:
    // конструктор
    vector(int n)
    {
        this->n = n;//Чтобы отличать переменную n из класса от переменной передаваемый в конструктор, я использовал this. Но в прнципе можно обойтись и без this
        this->v = new double[n];
        for (int i=0; i<n; i++)
        {
            v[i] = 0;
        }
    }
    
    // деструктор
    ~vector()
    {
        delete[] v;
    }
    
    // конструктор копирования
    vector(vector& vec)
    {
        this->n = vec.n;//это переменная n объекта vec
        this->v = new double[vec.n];
        for (int i=0; i<n; i++)
        {
            v[i] = vec.at(i);
        }
    }
    
    // возвращает размерность
    int len() { return n; }
    
    // возвращает элемент с индексом i
    double at(int i) { return v[i]; }
    
    // устанавливает значение элемента с индексом i
    void set(int i, double value) { v[i] = value; }
 
    // функция сложения
    vector add(vector& b)
    {
        int n = b.len();// n присваивается результат функции len объекта b класса vector. В данном случае это размерность.
        vector result(n);//Создание объекта result класса vector;
        for (int i=0; i<n; i++)
        {
            result.set(i, v[i]+b.at(i));//Вызов метода set, которая присваивает координатам новое значение. Номер координаты - первый параметр, ее значение - второй
        }
        return result;
    }
    
    // функция вычитания 
    vector sub(vector& b)
    {
        int n = b.len();
        vector result(n);
        for (int i=0; i<n; i++)
        {
            result.set(i, v[i]-b.at(i));
        }
        return result;
    }
    
    // функция скалярного произведения
    double sp(vector& b)
    {
        double result = 0.;
        for (int i=0; i<n; i++)
        {
            result += v[i] * b.at(i);
        }
        return result;
    }
    
    // функция умножения вектора на число
    vector mul(double b)
    {
        vector result(n);
        for (int i=0; i<n; i++)
        {
            result.set(i, v[i]*b);
        }
        return result;
    }
 
    // процедура ввода вектора
    void input(const char* prompt)
    {
        cout << prompt << endl;
        for (int i=0; i<n; i++)
            cin >> v[i];
    }
 
    // процедура вывода вектора
    void output()
    {
        for (int i=0; i<n; i++)
            cout << v[i] << '\t';
        cout << endl;
    }
    //Дружественная функция — это функция, которая не является членом класса, но имеет доступ к членам класса, объявленным в полях private или protected
    //Перегрузка - это возможность поддерживать несколько функций с одним названием, но разными сигнатурами вызова.
    // друзья-Это перегруженные операторы, которые позволяют использовать операцию сложения, вычитания, скалярного произведения, умножение на число (слева и справа), вывод и ввод соотвественно для класса vector. Переменная left - это то, что слева от знака, right - то что справа от знака. Переменные типа ostream, istream - это потоки вывода и ввода соотвественно.
    friend vector operator+(vector& left, vector& right);
    friend vector operator-(vector& left, vector& right);
    friend double operator*(vector& left, vector& right);
    friend vector operator*(vector& left, double right);
    friend vector operator*(double left, vector& right);
    friend ostream& operator<<(ostream& os, const vector& str);
    friend istream& operator>>(istream& is, const vector& vec);
    
};
 
vector operator+(vector& left, vector& right)
{
    return left.add(right);
}
 
vector operator-(vector& left, vector& right)
{
    return left.sub(right);
}
 
double operator*(vector& left, vector& right)
{
    return left.sp(right);
}
 
vector operator*(vector& left, double right)
{
    return left.mul(right);
}
 
vector operator*(double left, vector& right)
{
    return right.mul(left);
}
 
ostream& operator<<(ostream& os, const vector& vec)
{
    for (int i=0; i<vec.n; i++)
        os << vec.v[i] << '\t';
    os << endl;
    return os;
}
 
istream& operator>>(istream& is, const vector& vec)
{
    for (int i=0; i<vec.n; i++)
        is >> vec.v[i];
    return is;
}
 
// процедура вывода меню
void menu()
{
    cout << "-----------------------------------" << endl;
    cout << "1. Vvod znacheniya A" << endl;
    cout << "2. Vvod znacheniya B" << endl;
    cout << "3. Vyvod A+B" << endl;
    cout << "4. Vyvod A-B" << endl;
    cout << "5. Vyvod A*B" << endl;
    cout << "6. Vyvod c*A" << endl;
    cout << "7. Ispolzovat peregruzheniye function" << endl;
    cout << "8. Ispolzovat metody classa" << endl;
    cout << "0. Exit" << endl;
}
 
int main() {
    int n, in, mode;
    double c;
    cout << "Vvedite razmernost'" << endl;
    cin >> n;
 
    vector A(n), B(n);
    
    // используем перегруженные функкции
    mode = 1;
    
    // мы пока ничего не выбирали из меню
    in = -1;
    while(in != 0) {
        // смотрим, что в меню выбрали
        switch(in)
        {
        case 0:
            return 0;
            break;
 
        case 1:
            if (mode == 1)
            {
                cout << "Vvedite vector A" << endl;
                cin >> A;
            }
            else 
            {
                A.input("Vvedite vector A");
            }
            
            break;
 
        case 2:
            if (mode == 1)
            {
                cout << "Vvedite vector B" << endl;
                cin >> B;
            }
            else 
            {
                B.input("Vvedite vector B");
            }
            
            break;
        
        case 3:
            cout << "Result:" << endl;
            if (mode == 1)
            {
                cout << A + B << endl;
            }
            else 
            {
                A.add(B).output();
            }
            
            break;
 
        case 4:
            cout << "Result:" << endl;
            if (mode == 1)
            {
                cout << A - B << endl;
            }
            else 
            {
                A.sub(B).output();
            }
            
            break;
 
        case 5:
            cout << "Result:" << endl;
            if (mode == 1)
            {
                cout << A*B << endl;
            }
            else 
            {
                cout << A.sp(B) << endl;
            }
            
            break;
 
        case 6:
            cout << "Vvedite znacheniye c:" << endl;
            cin >> c;
            if (mode == 1)
            {
                cout << A*c << endl;
            }
            else 
            {
                A.mul(c).output();
            }
            
            break;
 
        case 7:
            mode = 2;
            break;
 
        case 8:
            mode = 1;
            break;
        }
 
        // вывод меню и ввод пункта
        menu();
        cin >> in;
    }
    
    
}
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.02.2016, 19:01
Ответы с готовыми решениями:

Явный конструктор копирования в c++
Когда в программе нужен явный конструктор копирования?

Компилятор игнорирует явный конструктор копирования
Уже в который раз возникают проблемы с конструкторами класса и вот очередная из них. Насколько я...

Конструктор класса, конструктор копирования запускается не тот который нужен
Есть такой конструктор: Neuron::Neuron(int iType_activation_funk) { this-&gt;iType_act =...

Зачем нужен конструктор?
Всем доброго дня. Ребят такая проблема объясните мне на пальцах для чего нужен конструктор в...

7
nd2
3431 / 2810 / 1249
Регистрация: 29.01.2016
Сообщений: 9,426
15.02.2016, 20:25 2
Цитата Сообщение от Leeeeroy Посмотреть сообщение
почему тут обезательно надо явный конструктор копирования?
Потому, что указатель в классе. Неявный будет копировать указатель, а не данные, на которые он указывает. В результате такого копирования, у объекта и у копии, будут указатели, связанные с одной и той же памятью. При освобождении памяти будет UB (попытка освобождения уже освобождённой).

Добавлено через 8 минут
По этой же причине, нужен и явный оператор присваивания.
1
1 / 1 / 1
Регистрация: 23.09.2014
Сообщений: 33
15.02.2016, 22:03  [ТС] 3
Цитата Сообщение от nd2 Посмотреть сообщение
Потому, что указатель в классе. Неявный будет копировать указатель, а не данные, на которые он указывает. В результате такого копирования, у объекта и у копии, будут указатели, связанные с одной и той же памятью. При освобождении памяти будет UB (попытка освобождения уже освобождённой).
Скажите еще пожалуйста, а зачем аж 3 перегруженных функции *, и как их сделать не друзьями?
C++
1
2
3
friend double operator*(vector& left, vector& right);
friend vector operator*(vector& left, double right);
friend vector operator*(double left, vector& right);
0
nd2
3431 / 2810 / 1249
Регистрация: 29.01.2016
Сообщений: 9,426
15.02.2016, 23:04 4
Цитата Сообщение от Leeeeroy Посмотреть сообщение
Скажите еще пожалуйста, а зачем аж 3 перегруженных функции *
Чтобы операнды разных типов, при использовании умножения, можно было писать.
Цитата Сообщение от Leeeeroy Посмотреть сообщение
и как их сделать не друзьями?
Первую и вторую можно: убрать friend и первый аргумент. Третью - нельзя.
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
15.02.2016, 23:16 5
Цитата Сообщение от Leeeeroy Посмотреть сообщение
явный конструктор копирования
явный - это explicit. А то, что у тебя - это явно определенный.
Цитата Сообщение от Leeeeroy Посмотреть сообщение
C++
1
this->n = n;//Чтобы отличать переменную n из класса от переменной передаваемый в конструктор, я использовал this. Но в прнципе можно обойтись и без this
В данном случае (присваивание) без this-> не обойтись (можно, правда замутить функцию, возвращающую ссылку на n, но это будет выглядеть бредово). А вот в инициализаторе конструктора уже this не будет нужен:
C++
1
2
vector(int n) : n(n) {
 ...
Если ты думаешь, что запись n = n; будет работать так же как this->n = n;, то ты сильно ошибаешься. Без this член n останется не проинициализирован.
0
1 / 1 / 1
Регистрация: 23.09.2014
Сообщений: 33
26.02.2016, 19:38  [ТС] 6
Цитата Сообщение от Tulosba Посмотреть сообщение
Если ты думаешь, что запись n = n; будет работать так же как this->n = n;, то ты сильно ошибаешься. Без this член n останется не проинициализирован.
Можете еще помочь, никак не пойму как реализовать метод []?
0
Вездепух
Эксперт CЭксперт С++
10314 / 5604 / 1530
Регистрация: 18.10.2014
Сообщений: 13,688
26.02.2016, 19:45 7
Цитата Сообщение от Leeeeroy Посмотреть сообщение
и как их сделать не друзьями?
В данном конкретном примере у этих функций нет никаких причин быть друзьями. Можно смело выкидывать все объявления friend из класса - от этого ничего не поменяется. Тот, кто их туда вписывал, сделал это чисто машинально, не задумываясь о том, что никакого смысла в них в данном случае нет.
0
1 / 1 / 1
Регистрация: 23.09.2014
Сообщений: 33
29.02.2016, 14:35  [ТС] 8
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В данном конкретном примере у этих функций нет никаких причин быть друзьями. Можно смело выкидывать все объявления friend из класса - от этого ничего не поменяется. Тот, кто их туда вписывал, сделал это чисто машинально, не задумываясь о том, что никакого смысла в них в данном случае нет
А как сделать проверку на размер векторов и я вот не пойму как разбить на файлы
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.02.2016, 14:35
Помогаю со студенческими работами здесь

Конструктор копирования, найти недочеты в программном коде
Здравствуйте, посмотрите пожалуйста, тут у меня конструктор копирования. Я нашел какой-то пример,...

Зачем нужен конструктор переноса?
Зачем нужен конструктор переноса если тоже самое можно реализовать в обычном конструкторе...

Не понимаю зачем нужен конструктор и типы методов
Объясните пожалуйста на пальцах зачем нужен Constructor и типы методов. В учебнике лишь написано,...

Объясните зачем нужен cin.get()
В чем разница между int a; for (int i = 0; i &lt; 5; i++) { cin &gt;&gt; a; ...


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

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru