Interfaces vs. Conceptos

¿Qué son los conceptos? Vamos a ver con un simple ejemplo, cómo podemos hacer una equivalencia entre las conocidas interfaces y los conceptos.

Imaginen esta "interfaz" (clase abstracta):
class IPortero {
public:
virtual IPortero() { }
virtual void ir_a_piso(int piso) = 0;
virtual int piso_destino() = 0;
};
Tenemos otra clase Ascensor que podemos "personalizar" con nuestro propio portero, así nuestra implementación de portero puede hacer lo que se le de la gana:
class Ascensor {
IPortero* m_portero;
public:
Ascensor(IPortero* portero) {
m_portero = portero;
}
void apretaron_boton_en_piso(int piso) {
m_portero->ir_a_piso(piso);
mover_ascensor(m_portero->piso_destino());
}
void mover_ascensor(int piso) { ... }
};
Con programación genérica, podemos reformular la interfaz convirtiéndola en un "concepto" y la clase Ascensor en una clase plantilla:
template<class TipoPortero>
class Ascensor {
TipoPortero m_portero;
public:
Ascensor() { }
void apretaron_boton_en_piso(int piso) {
m_portero.ir_a_piso(piso);
mover_ascensor(m_portero.piso_destino());
}
void mover_ascensor(int piso) { ... }
};
La pregunta es, ¿qué demonios es TipoPortero?. La respuesta es sencilla: TipoPortero puede ser cualquier tipo de dato que cumpla los siguientes requisitos:
  • Tenga un constructor por omisión (que se pueda construir un nuevo TipoPortero sin argumentos, o sea, TipoPortero()).
  • Tenga una función miembro TipoPortero::ir_a_piso(int), la cual recibe un "int" (o cualquier tipo de dato que se pueda construir desde un "int" implícitamente).
  • Y otra función miembro TipoPortero::piso_destino() que devuelve un entero.

¿Cómo especificamos la "interfaz" o los "requerimientos" de un concepto? Sencillamente no se puede, C++0x iba a soportar esto, pero ya no. Hoy en día la mejor respuesta es usar algunos comentarios en la clase Ascensor que especifiquen qué espera en sus parámetros de template. En este aspecto se podría decir que IPortero es mejor porque especifica explícitamente lo que el portero tiene que hacer (funciones a implementar, etc.).

¿Qué ventaja tiene el concepto con respecto a las interfaces? La clase genérica Ascensor ahora tiene el mismo portero adentro suyo (no un puntero a la interfaz). Las llamadas a las funciones miembro ir_a_piso y piso_destino son llamadas directas (no tienen el overhead de una llamada a una función virtual).


 18 October 2009 | cpp programacion conceptos interfaces