what - variable size c++
Objetos que pueden inicializarse pero no asignarse (5)
Necesito crear una clase cuyos objetos se puedan inicializar pero no asignar.
Pensé que quizás podría hacer esto al no definir el operador de asignación, pero el compilador usa el constructor para realizar la tarea.
Necesito que sea de esta manera:
Object a=1; // OK
a=1; // Error
¿Cómo puedo hacerlo?
Las funciones eliminadas están disponibles solo desde C ++ 11 en adelante, para compiladores más antiguos puede hacer que el operador de asignación sea private
.
struct Object
{
Object(int) {}
private:
Object& operator=(int);
};
El compilador lanzará un error para
Object a=1; //ok
a=2; // error
Pero aún puedes hacer
Object a=1,b=2;
b=a;
Debido a que el compilador no impide que el operador de asignación predeterminado sea generado. Por lo tanto, marcar la asignación predeterminada private
resolverá este problema.
struct Object
{
Object(int) {}
private:
Object& operator=(Object&);
};
¿Cómo puedo hacerlo?
Opción 1:
Haz que el constructor sea explicit
struct Object
{
explicit Object(int in) {}
};
Opcion 2:
delete
el operador de asignación.
struct Object
{
Object(int in) {}
Object& operator=(int in) = delete;
};
Puedes usar las dos opciones anteriores.
struct Object
{
explicit Object(int in) {}
Object& operator=(int in) = delete;
};
Opción 3:
Si no desea ninguna asignación después de la inicialización, puede delete
el operador de asignación con Object
como tipo de argumento.
struct Object
{
explicit Object(int in) {}
Object& operator=(Object const& in) = delete;
};
Eso evitará el uso de:
Object a(1);
a = Object(2); // Error
a = 2; // Error
Esperaba que esto fuera así al no definir el operador de asignación
Esto no funciona porque el operador de asignación de copia (que toma const Object&
como parámetro) se genera implícitamente. Y cuando escriba a = 1
, se intentará invocar al operador de asignación de copias generado, y 1
podría convertirse implícitamente en Object
mediante la conversión del constructor Object::Object(int)
; entonces a = 1;
funciona bien.
Puede declarar el operador de asignación tomando int
como eliminado (desde C ++ 11) explícitamente; que se seleccionará antes del operador de asignación de copias en la resolución de sobrecarga.
Si la función está sobrecargada, la resolución de sobrecarga se lleva a cabo primero, y el programa solo está mal formado si se seleccionó la función eliminada.
p.ej
struct Object {
Object(int) {}
Object& operator=(int) = delete;
};
También hay algunas otras soluciones con efectos secundarios. Puede declarar Object::Object(int)
como explicit
para prohibir la conversión implícita de int
a Object
y luego hacer que a = 1
falle. Pero tenga en cuenta que esto hará que Object a = 1;
también fallan porque la inicialización de copia no considera explicit
constructor explicit
. O puede marcar también el operador de asignación de copia eliminado, pero esto hará que la asignación entre Object
también falle.
Hacer a
const hará el truco
const Object a=1; // OK
Ahora no podrá asignar ningún valor a a
como se declara como const
. Tenga en cuenta que si declara a
const
, es necesario inicializar a
en el momento de la declaración.
Una vez que haya declarado a
const
y también la haya inicializado, no podrá asignar ningún otro valor a a
a=1; //error
Puede eliminar el operador de asignación:
#include <iostream>
using namespace std;
struct Object
{
Object(int) {}
Object& operator=(int) = delete;
};
int main()
{
Object a=1; // OK
a=1; // Error
}
Solución alternativa
Puede usar la palabra clave explícita :
#include <iostream>
using namespace std;
struct Object
{
explicit Object(int) {}
};
int main()
{
Object a(1); // OK - Uses explicit constructor
a=1; // Error
}
Actualizar
Según lo mencionado por user2079303 en los comentarios:
Vale la pena mencionar que la solución alternativa no evita la asignación regular de copiar / mover como
a=Object(1)
Esto se puede evitar usando: Object& operator=(const Object&) = delete;