Объекты, которые могут быть инициализированы, но не назначены
Мне нужно создать класс, объекты которого могут быть инициализированы, но не назначены.
Я подумал, может быть, я мог бы сделать это, не определяя оператор присваивания, но компилятор использует конструктор для выполнения задания.
Мне нужно, чтобы это было так:
Object a=1; // OK
a=1; // Error
Как я могу это сделать?
Ответы
Ответ 1
Вы можете delete оператор присваивания:
#include <iostream>
using namespace std;
struct Object
{
Object(int) {}
Object& operator=(int) = delete;
};
int main()
{
Object a=1; // OK
a=1; // Error
}
Альтернативное решение
Вы можете использовать explicit ключевое слово
#include <iostream>
using namespace std;
struct Object
{
explicit Object(int) {}
};
int main()
{
Object a(1); // OK - Uses explicit constructor
a=1; // Error
}
Обновление
Как указано пользователем2079303 в комментариях:
Возможно, стоит упомянуть, что альтернативное решение не предотвращает регулярное назначение копирования/перемещения, например a=Object(1)
Этого можно избежать, используя: Object& operator=(const Object&) = delete;
Ответ 2
Создание a
const сделает трюк
const Object a=1; // OK
Теперь вы не сможете присвоить значение a
, поскольку a
объявлен как const
. Обратите внимание, что если вы объявляете a
как const
, необходимо инициализировать a
во время объявления.
После того, как вы объявили a
как const
и также инициализировали его, вы не сможете назначить любое другое значение a
a=1; //error
Ответ 3
Я надеялся, что это будет так, не определяя оператор присваивания
Это не работает, потому что оператор назначения копирования (который принимает const Object&
как параметр) неявно генерируется. И когда вы пишете a = 1
, сгенерированный оператор присваивания копии будет вызван, и 1
может быть неявно преобразован в Object
через конструктор преобразования Object::Object(int)
; то a = 1;
работает нормально.
Вы можете объявить оператор присваивания, принимающий int
как deleted (начиная с С++ 11) явно; который будет выбран до операции присваивания копии при разрешении перегрузки.
Если функция перегружена, сначала происходит разрешение перегрузки, и программа только плохо сформирована, если выбрана удаленная функция.
например.
struct Object {
Object(int) {}
Object& operator=(int) = delete;
};
Существуют и другие решения с побочными эффектами. Вы можете объявить Object::Object(int)
как explicit
, чтобы запретить неявное преобразование от int
до Object
, а затем сделать a = 1
сбой. Но обратите внимание, что это приведет к ошибке Object a = 1;
, так как инициализация копирования не учитывает конструктор explicit
. Или вы также можете пометить оператор присваивания копии, но это приведет к сбою между Object
.
Ответ 4
Как я могу это сделать?
Вариант 1:
Сделайте конструктор explicit
struct Object
{
explicit Object(int in) {}
};
Вариант 2:
delete
оператор присваивания.
struct Object
{
Object(int in) {}
Object& operator=(int in) = delete;
};
Вы можете использовать оба указанных параметра.
struct Object
{
explicit Object(int in) {}
Object& operator=(int in) = delete;
};
Вариант 3:
Если вы не хотите назначать после инициализации, вы можете delete
оператор присваивания с Object
в качестве типа аргумента.
struct Object
{
explicit Object(int in) {}
Object& operator=(Object const& in) = delete;
};
Это предотвратит использование:
Object a(1);
a = Object(2); // Error
a = 2; // Error
Ответ 5
Удаленные функции доступны только с С++ 11, для более старых компиляторов вы можете сделать оператор присваивания private
.
struct Object
{
Object(int) {}
private:
Object& operator=(int);
};
Компилятор теперь выдает ошибку для
Object a=1; //ok
a=2; // error
Но вы все равно можете
Object a=1,b=2;
b=a;
Поскольку оператор присваивания по умолчанию не может быть сгенерирован компилятором. Таким образом, выделение по умолчанию private
решит эту проблему.
struct Object
{
Object(int) {}
private:
Object& operator=(Object&);
};