Подтвердить что ты не робот

Объекты, которые могут быть инициализированы, но не назначены

Мне нужно создать класс, объекты которого могут быть инициализированы, но не назначены.

Я подумал, может быть, я мог бы сделать это, не определяя оператор присваивания, но компилятор использует конструктор для выполнения задания.

Мне нужно, чтобы это было так:

Object a=1;    // OK
a=1;           // Error

Как я могу это сделать?

4b9b3361

Ответ 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&);
};