Я хочу нормально перегрузить общий оператор присваивания копии. Сначала я использовал интерфейс, который требует только постоянной ссылки на источник, и явно отключил интерфейс, который принимает модифицируемую ссылку, но не могу пройти компиляцию. Компилятор сообщает "ошибка: использование удаленной функции ClassA& ClassA::operator=(ClassA&)"
Конечно, я могу быть скомпилирован, если не удалю явно интерфейс, но это не моя цель. Я хотел бы явно удалить его, чтобы избежать неожиданного его использования.
Почему для операции копирования-присваивания требуется модифицируемая ссылка на источник, а не постоянная ссылка? Операция присваивания просто должна получить доступ к источнику только для чтения!
Тот же вопрос про копи-конструктор, опускаю для упрощения.
Что не так с моим кодом? или мы НЕ можем удалить его?
Мой пример кода следующий:
class ClassA {
public:
ClassA() = default;
ClassA( ClassA & ) = default;
ClassA & operator=( ClassA & )
= delete // Must comment-out this, or we can't pass the compilation.
// { cout << "ClassA & operator=( ClassA & ) executed." << endl; return *this; }
;
ClassA & operator=( ClassA && ) {
cout << "ClassA & operator=( ClassA && ) executed." << endl;
return *this;
};
ClassA & operator=( const ClassA & ) {
cout << "ClassA & operator=( const ClassA & ) executed." << endl;
return *this;
};
ClassA & operator=( const ClassA && ) {
cout << "ClassA & operator=( const ClassA && ) executed." << endl;
return *this;
};
};
int main() {
ClassA oa, ob;
ob = oa;
return EXIT_SUCCESS;
};
Принятие ссылки const
rvalue не имеет особого смысла из-за характера ссылок rvalue.
Вам нужно принять решение. Либо используйте ClassA &operator=(const ClassA &) = delete
, что не позволяет компилятору генерировать operator=()
и означает, что у класса его нет, либо вы определяете и реализуете оператор. Эти два понятия являются взаимоисключающими. Вы не можете ожидать, что оператор будет явно удален, а затем явно реализован.
or we can NOT delete it?
Вам просто не нужно этого делать. Если вы предоставите определяемый пользователем оператор присваивания копии, то никакие другие не будут неявно объявленный, т.е. будет существовать только определяемый пользователем.
Если вы это сделаете, оператор присваивания копии, который вы явно пометили как delete
, будет участвовать в разрешении перегрузки; когда он выбран, компиляция завершается неудачно. Для ob = oa;
лучше подходит operator=( ClassA & )
, если его не существует, operator=( const ClassA & )
будет использоваться и работать нормально.
Итак, в этом случае вы можете просто сделать
class ClassA {
public:
ClassA & operator=( ClassA && ) {
cout << "ClassA & operator=( ClassA && ) executed." << endl;
return *this;
}
ClassA & operator=( const ClassA & ) {
cout << "ClassA & operator=( const ClassA & ) executed." << endl;
return *this;
}
};
Of course, I can get compiled if I don't expicitly delete the interface, but that is not my purpose. I'd like to expicitly delete it, to avoid unexpected using it.
Вы не можете неожиданно использовать то, чего не существует. Если ваш класс определяет ClassA & operator=( const ClassA & )
, то ClassA & operator=( ClassA & )
вообще не будет существовать (компилятор этого не сгенерирует). Нет причин предоставлять и удалять его.
Если вы явно удалите его и вызовете:
ob = oa;
// The same as
ob.operator=(oa);
Конечно, ClassA & operator=( ClassA & )
— лучшее совпадение, так как oa
— неконстантное lvalue. Так как он удален, это будет ошибкой.
Если он вообще не объявлен, ClassA & operator=( const ClassA & )
теперь становится лучшим совпадением. Поэтому он никогда не будет пытаться использовать ClassA & operator=( ClassA & )
, поскольку его не существует.
Если бы вы действительно хотели, у вас все еще мог бы быть ClassA & operator=( ClassA & ) = delete;
, и вам пришлось бы вручную назначать ссылки из констант:
ob = static_cast<const ClassA&>(oa);
// Will now select `ClassA & operator=( const ClassA & )`
Это показывает, что вам не нужен неконстантный оператор присваивания lvalue. Но на самом деле в этом нет смысла, так как он все равно будет использоваться как ссылка на константу, если ClassA & operator=( ClassA & )
не объявлен.
зачем вам это нужно? почему изменение себя изменит другой экземпляр?