Pregunta ¿Por qué no se puede usar una función no miembro para sobrecargar el operador de asignación?


El operador de asignación puede estar sobrecargado utilizando una función de miembro pero no un miembro no miembro friend función:

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

Causa este error:

error C2801: 'operator =' debe ser un miembro no estático

Por qué no puede friend función se utiliza para sobrecargar el operador de asignación? El compilador permite sobrecargar otros operadores como += y -= utilizando friend. ¿Cuál es el problema / limitación inherente en el soporte? operator=?


26
2017-10-14 13:29


origen


Respuestas:


Porque el predeterminado operator= proporcionado por el compilador (la copia de miembro) siempre tendrá prioridad. Es decir. tu amigo operator= nunca sería llamado.

EDITAR: Esta respuesta está respondiendo al

¿Cuál es el problema / limitación inherente en support = operator?

parte de la pregunta. Las otras respuestas aquí citan la parte del estándar que dice que no puedes hacerlo, pero esto es muy probable por qué esa porción del estándar fue escrita de esa manera.


26
2017-10-14 13:36



En primer lugar, debe tenerse en cuenta que esto no tiene nada que ver con que el operador se implemente como un amigo específicamente. Se trata realmente de implementar la función de copia como función miembro o como función no miembro (independiente). Que esa función independiente sea o no amiga es completamente irrelevante: podría ser, tal vez no lo sea, dependiendo de lo que quiera acceder dentro de la clase.

Ahora, la respuesta a esta pregunta se encuentra en el libro de D & E (El diseño y la evolución de C ++) La razón de esto es que el compilador siempre declara / define un operador de asignación de copia miembro para la clase (si no declara su propio operador de copia-asignación de miembros).

Si el lenguaje también permitía declarar al operador de asignación de copias como una función independiente (no miembro), podría terminar con lo siguiente

// Class definition
class SomeClass {
  // No copy-assignment operator declared here
  // so the compiler declares its own implicitly
  ...
};

SomeClass a, b;

void foo() {
  a = b;
  // The code here will use the compiler-declared copy-assignment for `SomeClass`
  // because it doesn't know anything about any other copy-assignment operators
}

// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);

void bar() {
  a = b;
  // The code here will use your standalone copy-assigment for `SomeClass`
  // and not the compiler-declared one 
}

Como se ve en el ejemplo anterior, la semántica de la asignación de copia cambiaría en el medio de la unidad de traducción: antes de la declaración de su operador independiente, se utiliza la versión del compilador. Después de la declaración, se usa su versión. El comportamiento del programa cambiará dependiendo de dónde coloque la declaración de su operador de copiado independiente.

Esto se consideró inaceptablemente peligroso (y lo es), por lo que C ++ no permite que el operador de asignación de copias sea declarado como una función independiente.

Es cierto que en su ejemplo particular, que pasa a usar un amigo función específicamente, el operador se declara muy temprano, dentro de la definición de la clase (ya que así es como se declaran los amigos). Entonces, en su caso, el compilador sabrá de inmediato la existencia de su operador. Sin embargo, desde el punto de vista del lenguaje C ++, el problema general no está relacionado con las funciones de amigo de ninguna manera. Desde el punto de vista del lenguaje C ++, se trata de funciones miembro frente a funciones que no son miembros, y la sobrecarga de la asignación de copias por parte de no miembros está completamente prohibida por los motivos descritos anteriormente.


32
2017-10-14 13:51



$ 13.5.3 - "Un operador de asignación debe ser implementado por una función de miembro no estático con exactamente un parámetro. Debido a que un operador de asignación de copias = se declara implícitamente para una clase si el usuario no lo declara (12.8), un operador de asignación de clase base siempre está oculto por el operador de asignación de copias de la clase derivada ".


8
2017-10-14 13:40



Porque hay algunos operadores que DEBEN ser miembros. Estos operadores son:
operator[]
operator=
operator()
operator-> 

y escriba los operadores de conversión, como operator int.

Aunque uno podría ser capaz de explicar por qué exactamente operator = debe ser miembro, su argumento no puede aplicarse a otros en la lista, lo que me hace creer que la respuesta a "Why" es "Just because".

HTH


6
2017-10-14 13:38



operator= es una función de miembro especial que el compilador proporcionará si no la declara usted mismo. Debido a este estado especial de operator= tiene sentido ro requerir que sea una función miembro, por lo que no hay posibilidad de que haya un miembro generado por el compilador operator= y un amigo declarado por el usuario operator= y sin posibilidad de elegir entre los dos.


3
2017-10-14 13:42



¿Por qué la función de amigo no se puede usar para sobrecargar al operador de asignación?

Respuesta corta: Simplemente porque.

Respuesta algo más larga: esa es la forma en que se solucionó la sintaxis. Algunos operadores tiene que ser funciones miembro. El operador de asignación es uno de los


1
2017-10-14 13:40



La intención de operator= es una operación de asignación al objeto actual. Entonces, el LHS o lvalue es un objeto del mismo tipo.

Considere un caso donde el LHS es un número entero o algún otro tipo. Ese es un caso manejado por operator int() o un correspondiente operator T() función. Por lo tanto, el tipo de LHS ya está definido, pero no es miembro operator= la función podría violar esto.

Por lo tanto, se evita.


0
2017-07-04 13:16



Porque hay ya una función implícita de sobrecarga del operador para '=' en la clase para hacer copia superficial. Entonces, incluso si sobrecarga usando una función amiga nunca podrás llamarlo ya que cualquier llamada hecha por nosotros llamaría al método implícito de copia superficial en lugar de a la función amigo sobrecargado.


0
2018-05-28 04:35



Esta publicación se aplica a C ++ 11

¿Por qué alguien querría un no miembro? operator=? Bueno, con un miembro operator= entonces el siguiente código es posible:

Test const &ref = ( Test() = something ); 

que crea una referencia colgante. Un operador no miembro arreglaría esto:

Test& operator=(Test &obj1, Test obj2)

porque ahora el prvalue Test() no podrá unirse a obj1. De hecho, esta firma exigiría que nunca devolviéramos una referencia pendiente (a menos que se nos haya proporcionado una, por supuesto): la función siempre devuelve un valor l "válido" porque exige que se llame con un valor l.

Sin embargo, en C ++ 11 ahora hay una manera de especificar que una función miembro solo puede invocarse en lvalues, por lo que podría lograr el mismo objetivo escribiendo la función de miembro:

Test &operator=(Test obj2) &
//                        ^^^

Ahora el código anterior con referencia colgante no se compilará.


NÓTESE BIEN. operator= debe tomar el lado derecho por cualquier valor o referencia constante. Tomar por valor es útil cuando se implementa copiar e intercambiar idioma, una técnica para escribir fácilmente operadores de asignación de copia y asignación de movimiento seguros (pero no necesariamente los más rápidos).


0
2018-02-19 03:59