Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


4.9  Operadores

§1  Sinopsis

Los operadores son un tipo de tokens ( 3.2) que pueden aparecer en las expresiones, e indican al compilador la realización de determinadas operaciones matemáticas, lógicas ( 4.9.8) y numéricas (4.9.1). Se aplican a variables u otros objetos denominados operandos y su efecto es una combinación de las siguientes acciones:

  • Producir un resultado-valor
  • Alterar un operando
  • Designar un objeto o función.
Ejemplos
§1a

y = a + b;

En esta sentencia, el operador suma + ( 4.9.1) produce un valor nuevo, pero no altera ninguno de los operandos (a y b); a su vez, el nuevo valor es asignado a la variable y mediante el operador de asignación = ( 4.9.2). En este caso el operando de la izquierda sí se ve alterado.

§1b

x++;

Aquí el operador postincremento ++ ( 4.9.1) produce un nuevo valor que es aplicado sobre el propio operando, de forma que queda alterado. Cuando un operador altera un operando se dice que tiene efectos laterales.

Nota: por lo general, los operadores aparecen a la derecha de expresiones de asignación (por ejemplo: y = 2 * y + x), pero en ocasiones estos "efectos laterales" se utilizan para conseguir expresiones muy compactas y de un cierto nivel de sofisticación, que incluso no necesitan del operador de asignación para producir el resultado. En estos casos su lógica es un poco más difícil de seguir que cuando estos efectos no se utilizan directamente (Ver ejemplo 4.9.6).

§1c

z = (*fptr)(x, y);

Aquí, el operador de indirección * es aplicado sobre el operando fptr que es un puntero-a-función. El resultado es un designador de función al que se aplica el operador ( ) de invocación de función con dos operandos x e y que actúan como argumentos. A su vez el resultado de este operador (invocación de función) es utilizado como argumento derecho del operador de asignación = que finalmente modifica uno de sus operandos (el operando izquierdo z).

§2  Clasificación

C++ dispone de un conjunto muy rico de operadores que se pueden clasificar en unitarios, binarios y ternarios, según que necesiten uno, dos o tres operandos. Los operadores unitarios (denominados también unarios) se clasifican en dos tipos según la posición del operador (representado aquí por @) respecto del operando (representado aquí por n):

@n:  Operador prefijo.  Ejemplo:  ++x

n@:  Operador posfijo.  Ejemplo:  x++


Antes de seguir refiriéndonos a ellos, tal vez sean procedentes un par observaciones que más adelante nos ayudarán a comprender mejor algunos conceptos:

  • Los operadores pueden (en cierta forma) considerarse como funciones que tienen un álgebra un tanto especial. De hecho, al tratar la sobrecarga de operadores, veremos que precisamente la forma en que se definen es mediante una función, la función-operador ( 4.9.18). En este sentido podríamos imaginar que la expresión y = a + b es otra forma de representar algo como: y = suma(a, b). Del mismo modo, la asignación x = y sería algo así: asigna(x, y). Siguiendo con nuestra analogía, podríamos suponer que los operadores unitarios, binarios y ternarios serían funciones que aceptarían unos, dos o tres argumentos respectivamente y que la sobrecarga de operadores no es sino una forma encubierta de sobrecarga de funciones.

  • Aunque las funciones C++ se designan con identificadores (nombres) que siguen las reglas generales ya señaladas ( 3.2.2), estas seudo-funciones se identifican con símbolos ( +, =, ::, *, ->, etc) [3]. Muchos de ellos están compuesto de un solo token (que puede estar repetido + y ++) aunque los hay de dos. Estos últimos son: new[]delete[]() y [].

  • Antes de realizar la operación encomendada, los operadores pueden modificar el tipo de los operandos para que sean homogéneos, de forma que la operación pueda realizarse. Por ejemplo, al indicar i + f donde i sea un entero y f un float. Estas promociones se denominan conversiones estándar ( 2.2.5) y son realizadas automáticamente por el compilador, pero deben ser tenidas en cuenta para evitar sorpresas.


§3  En general los operadores aceptan un tipo de operando determinado y específico, produciendo y/o modificando un valor de acuerdo con ciertas reglas, pero C++ permite redefinir la mayoría de ellos . Es decir, permite que puedan aceptar otro tipo de operandos y seguir otro comportamiento sin que pierdan el sentido y comportamiento originales cuando se usan con los operandos normales (los tipos básicos preconstruidos en el lenguaje). Esta circunstancia recibe el nombre de sobrecarga ( 4.9.18) del operador [1].

  No son sobrecargables los siguientes:

. Operador de selección de miembros ( 4.9.16c)
.* Operador de dereferencia ( 4.9.11)
:: Operador de acceso a ámbito ( 4.9.19)
?: Operador conditional ( 4.9.6)
# Directiva de preprocesado ( 4.9.10)
§4  Polimorfismo en los operadores

  Debe tener en cuenta que aún sin estar sobrecargado, dependiendo del contexto (número y tipo de operandos), un operador C++ puede tener más de un significado [2]. Veamos dos ejemplos:

  El símbolo ámpersand & puede ser interpretado como:

  • AND entre bits                 A & B            ( 4.9.3)
  • Operador de referencia      y = &x          ( 4.9.11b)
  • Declarador de referencia   int& y = x   ( 4.2.3)

  El asterisco * puede ser interpretado como:

  • Declaración de un tipo puntero-a   tipo* ptr   ( 4.2.1a)
  • Operador de indirección                x = *ptr    ( 4.9.11a)
  • Operador de multiplicación            x * y         ( 4.9.1)
§5  Precedencia

La precedencia es una regla de orden que se asocia con los operadores para establecer cual se aplicará primero en caso de aparecer varios en una misma expresión (una especie de "orden de importancia" de los operadores). Por ejemplo:

x =  2 + 3 * 4;

¿Cual será el resultado,  20 o 14?


La primera regla en este sentido es que las expresiones se evalúan de izquierda a derecha, aunque no siempre. Por ejemplo, la regla izquierda → derecha nos conduciría a que en la expresión anterior, el valor de x es 20, lo cual no es cierto, ya que en C++ la multiplicación tiene mayor precedencia que la suma, así que el resultado es 14.

En C++ existen 16 niveles de precedencia, de modo que la regla izquierda → derecha solo se aplica en caso de operadores del mismo nivel ( 4.9.0a).

El operador de jerarquía más alta es el paréntesis, lo que aclara y justificada la tradicional costumbre algabráica de utilizar paréntesis para forzar el orden de las operaciones. Por ejemplo, si queremos que en la expresión anterior se ejecute primero el operador suma:

x =  (2 + 3) * 4;    // el resultado es 20

Aunque las reglas de precedencia se suponen conocidas por los programadores C++, aconsejamos generosidad a la hora de utilizar paréntesis en las expresiones. Además de facilitar la legibilidad evitan posibles errores. Así, aunque las dos sentencias que siguen son equivalentes, la segunda es de lectura más "relajante".

x =  2 + 3 * 4;
x =  2 + (3 * 4);


  Inicio.


[1]  No confundir con la sobrecarga de funciones ( 4.4.1), un concepto distinto aunque emparentado. Precisamente la sintaxis adoptada por C++ para sobrecargar un operador adopta la forma de una función. La denominada función-operador ( 4.9.18).

[2]  Podemos suponer que en C++ los operadores vienen ya sobrecargados de origen.

[3]  La razón es de tipo histórico. Precisamente los primeros lenguajes de programación que podríamos considerar de "alto nivel", fueron del tipo del FROTRAN; su propio nombre, contracción de "Formula Translator", denota claramente que sus creadores trataban de crear un lenguaje que se pareciera al de las matemáticas (literalmente traducir fórmulas matemáticas), donde el álgebra y sus símbolos ( +, -, =  etc) para representar determinadas "operaciones" estaban ya muy bien establecidos.