¿Es posible escribir un operador de conversión automática fuera de una estructura?

7 minutos de lectura

avatar de usuario
brigadier

La situación exacta es la siguiente: he definido en las estructuras API del sistema CGPoint y CGSizey quiero poder escribir my_point = my_size. no puedo modificar CGPoint struct, solo puede escribir un operador externo. Puedo escribir operadores binarios (+, -…) pero operator= debe declararse dentro de la estructura. Entonces, ¿hay alguna otra solución?

  • ¿Cuál es la conexión entre un punto y un tamaño? ¿Cómo puede el tamaño ser un punto? Suena como diferentes dimensiones.

    – Bo Person

    25 de mayo de 2011 a las 7:43


  • @BoPersson No veo la relevancia de su pregunta. ¿Cómo cambia su relación la sintaxis con la que se escribe dicho operador?

    – usuario64742

    12 de febrero de 2021 a las 6:33


Para hacer la expresión a = b; compilar necesita tener un operator= en el tipo de a que toma un elemento del tipo de bo un tipo implícitamente convertible de b.

Se descarta el primer caso, ya que operator= debe ser miembro de la clase, y dado que no puede modificar GLPoint entonces no puedes agregar GLPoint& GLPoint::operator=( GLSize ).

El segundo caso sufre el mismo tipo de problemas. Una conversión implícita de GLSize a GLPoint se puede implementar como un constructor implícito en GLPoint (descartado), o como miembro operator GLPoint() en GLSizeque requiere la modificación de GLSize. Las conversiones tampoco se pueden agregar como funciones gratuitas.

Las alternativas están usando sintaxis sin operador, como agregar una función libre assign (o copy): GLPoint& assign( GLPoint&, GLSize const & ).

La siguiente pregunta es por qué querrías hacerlo. Si los diseñadores de GLPoint y GLSize no consideró que un tamaño debe ser asignable a un punto, entonces ¿por qué siente que deben ser asignables? En general, es una buena idea mantener los tipos separados, ya que eso permitirá que el compilador detecte errores que pueda cometer en su código.

Si permite conversiones implícitas de GLSize a GLPointes posible que por error escriba algo como: distance( point1, size2 ) donde quisiste decir distance( point1, point2 ), y debido a que hay una conversión, el compilador con gusto convertirá y aplicará. Entonces verás resultados extraños, y pasarás bastantes bonito horas de depuración tratando de determinar dónde está mal la lógica.

A menos que el dominio tenga una definición muy clara de lo que significa cada operador en ese contexto, evitaría a toda costa la sobrecarga de operadores. Voluntad todo el mundo al leer su código comprenda de inmediato lo que GLPoint(1,2) + GLSize(5) representa sin ninguna duda o ambigüedad? Si ese no es el caso, si la gente se sorprenderá o incluso dudará, evite la sobrecarga de operadores y use funciones con nombre: move_up( GLPoint&, GLSize ) (o lo que signifique punto+tamaño para ti)

  • +1, excelente comentario sobre las trampas de los operadores de conversión

    – Nim

    25 de mayo de 2011 a las 7:46

  • Excelente comentario en general, con el análisis de la semántica subyacente. (Obviamente basado en los nombres, pero si sus suposiciones son incorrectas, los nombres están muy mal elegidos).

    – James Kanze

    25 de mayo de 2011 a las 8:01

  • Entiendo los errores de concepto 🙂 Pero seguirlos genera cierta incomodidad (código grande: debo escribir CGPoint (my_size.width, my_size.height) cada vez). He resuelto el problema en parte mediante la función de plantilla que convierte cualquier tipo en CGPoint. Sí, entiendo los errores de concepto 🙂

    – brigadier

    25 de mayo de 2011 a las 8:32


  • @brigadir: o simplemente agregue una función: inline GLPoint pointFromSize( GLSize const & ); y úsalo: point = pointFromSize( size1 ); que es muy fácil de analizar para un ser humano. El punto es que la sobrecarga de operadores reduce la escritura, pero hace que el código sea más oscuro, para interpretar una línea a+b usted tiene que volver a leer las definiciones. Además, ¿cuál es el resultado de point+sizeEs una pointa sizedepende del orden de los argumentos?

    – David Rodríguez – dribeas

    25 de mayo de 2011 a las 8:51


  • Why would you want to do so. If the designers of GLPoint and GLSize did not consider that a size should be assignable to a point, then why do you feel that they should be assignable? Aquí hay un ejemplo de por qué uno querría hacer esto: LARGE_INTEGER es una estructura que no se puede convertir implícitamente a/desde LONGLONG a pesar de que contiene uno en el QuadPart miembro. Uno (yo) querría escribir un operador de conversión para que sea más fácil usar el PLI escriba funciones y asignaciones en lugar de tener que usar una línea separada adicional, como cuando llama SetFilePointerEx.

    – Synetech

    17 de julio de 2013 a las 17:10

Cuando asignas un CGSize a un CGPoint – ¿lo que sucede? Destile eso en algún operador y ahí lo tiene, por ejemplo

CGPoint& operator|=(CGPoint& cPoint, CGSize const& cSize)
{
  // now set attributes of cPoint that you can extract from cSize

  return cPoint;
}

¿Qué tiene de difícil esto? Aquí hay un ejemplo: http://www.ideone.com/FZN20

  • Es una buena solución para casos simples, quiero operar con CGSize en expresiones…

    – brigadier

    25 de mayo de 2011 a las 8:39

  • I want to [use it] in expressions Exactamente. Por ejemplo, en mi caso, quiero hacer algo como LONGLONG size=blah(); SetFilePointerEx(fh, size, NULL, FILE_BEGIN); en lugar de tener que hacer LONGLONG size=blah(); LARGE_INTEGER tli={0}; tli.QuadPart=size; SetFilePointerEx(fh, tli, NULL, FILE_BEGIN); Si puedo escribir algo como LARGE_INTEGER operator=(LONGLONG ll) {LARGE_INTEGER li={0}; li.QuadPart=ll; return li;} (o un operador de conversión), entonces crearía un código más limpio que es más fácil de usar y comprender.

    – Synetech

    17 de julio de 2013 a las 17:23

  • yo prefiero operator<<

    – kyb

    15 de diciembre de 2016 a las 16:35

Si puede derivar o envolver CGPoint y usar la nueva clase en su lugar a lo largo de su código, entonces puede proporcionar los operadores que desee. La nueva clase puede tener un operador de conversión para CGPoint facilitando la interacción con las funciones existentes.

  • Esto es propenso a ser más problemático que útil. La herencia es la segunda relación más acoplada y debe evitarse a menos que tenga sentido, y en este caso no creo que lo tenga. Tenga en cuenta que el código existente aún devolverá el tipo no derivado, y luego estará mezclando puntos que se pueden asignar con puntos que no se pueden asignar. Peor que eso, el sistema actual podría esperar contenedores de GLPointsi es por valor, entonces no aceptará el nuevo tipo, si es por puntero, e intenta delete internamente, entonces estás en la tierra del Comportamiento Indefinido…

    – David Rodríguez – dribeas

    25 de mayo de 2011 a las 7:55

  • @David: sin duda, son consideraciones que deberían guiar la elección de la derivación frente a la envoltura/composición, y podrían hacer que las técnicas que he enumerado sean inapropiadas para un problema en particular. El equilibrio depende de cuántos puntos de interacción hay con funciones que necesitarían GLPoints “reales”, frente a la cantidad de código interno de la aplicación que podría beneficiarse de la comodidad de esta notación de asignación. Hasta el OP para evaluar su caso.

    – Tony Delroy

    25 de mayo de 2011 a las 9:11

Otras respuestas parecen perder la solución obvia: agregue una función para convertir CGPoint en CGSize. Por supuesto, eso no es exactamente lo que quieres (size = point), pero como no puede modificar ninguna de las dos clases, esta es la única forma:

CGSize ToSize( const CGPoint &pt )
{
  CGSize res = ...
  // do the conversion
  return res;
}

¿Ha sido útil esta solución?