Я пытаюсь понять конструкторы копирования, пожалуйста, поймите меня, как это работает.
Дело 1
class fruit{
public: int i;
fruit(int j){
i = j;
}
};
int main(){
fruit f1 = fruit(2); // works fine when no user defined copy constructor
return 0;
}
Случай 2
class fruit{
public: int i;
fruit(fruit &f){
i = f.i + 1;
}
fruit(int j){
i = j;
}
};
int main(){
fruit f1 = fruit(2); // error no matching call fruit::fruit(fruit) why?
return 0;
}
Случай 3
class fruit{
public: int i;
fruit(){
i = 0;
}
};
int main(){
fruit f2;
fruit f1 = fruit(f2); // works fine when no user defined copy constructor
return 0;
}
Случай 4
class fruit{
public: int i;
fruit(){
i = 0;
}
fruit(fruit &f){
i = f.i + 1;
}
};
int main(){
fruit f2;
fruit f1 = fruit(f2); // error no matching call fruit::fruit(fruit)
return 0;
}
Technically 'fruit(f2)' must be valid because
f2 can be passed by reference to fruit(fruit &f). right? but why error?
Почему я получаю ошибку в Case 2
и Case 4
? это потому, что я создал пользовательский конструктор копирования? Если причиной является пользовательский конструктор копирования, даже компилятор предоставляет конструкторы копирования по умолчанию. как fruit(fruit &)
внутри. Так что даже тогда конструкторы копирования доступны для программы, предоставляемой компилятором. Почему это не вызывает ошибки в случаях Case 1
и Case 3
Я понимаю, что все конструкторы заблокированы с =
когда пользователь определяет конструктор копирования. =
может вызвать только конструктор копирования. но должен быть один конструктор копирования для класса может быть пользователем или компилятором. Если он предоставляется компилятором, то он также должен вызывать ошибку. но это не так?
Это не проблема, связанная с конструкторами копирования; Ссылки non- const
lvalues не могут привязываться к временным.
Следующий код был бы скомпилирован:
fruit f1;
fruit f2(f1);
потому что f1
не является временным, когда вы его передаете.
Тем не менее, вы хотите, чтобы временные файлы работали, поэтому напишите свой конструктор копирования следующим образом:
fruit(const fruit& f) {
i = f.i + 1;
}
Ваши случаи 1 и 3 преуспевают, потому что компилятор может создать собственный конструктор копии по умолчанию, увидев, что вы его не предоставили, что в отличие от вас - оно работает правильно. :-)
fruit(int)
, который работает нормально .... но затем вы копируете получившийся временный объект в f1
и это происходит по той же причине, что и в других случаях. Если бы вы только что написали fruit f1(2);
тогда это сработало бы, потому что для этого не нужно копировать какие-либо фрукты.
fruit f1 = fruit(f2);
Для фруктов (f2) будет создано временное, которое не может быть привязано к неконстантной ссылке. Для этого вам необходимо использовать следующую копию:
fruit(const fruit& f)
fruit(fruit&)
не является конструктор копирования, просто обычный конструктор , который требует L-значениеfruit
ссылки.fruit(fruit const&)
является конструктором копирования, аfruit(fruit&&)
является конструктором перемещения, который будет вызываться (если предоставлен) с учетом ваших примеров. Это потому, что вы создаете временные объекты, которые не являются l-значениями, и поэтому не могут быть привязаны к ссылкам l-значения (&
), но могут быть привязаны к ссылкам r-значения (&&
).