C++: Punteros a funciones miembro

Éste es uno de los temás más avanzados de C++, casi un arcano. Tanto en C como en C++ tenemos punteros a funciones, que nos permiten seleccionar dinámicamente la función a invocar entre varias que tienen el mismo encabezado. El ejemplo típico de aplicación es hacer una función que ordene una colección de diferentes formas, usando para comparar elementos una función invocado a través de un puntero.

Esto puede hacerse en C++, pero a priori sólo con funciones static. Si queremos hacerlo con funciones miembro de una clase, debemos usar este mecanismo exclusivo de C++. La sintaxis para declarar un puntero a función miembro es similar a la de los punteros a función, con el agregado de especificar la clase:

// Sintaxis Genérica
// retornoFuncion (NombreClase::*nombreVariablePunteroAMiembro)( argumentosFuncion );

// Ejemplo concreto
LRESULT (CCoConsola3D::*onMouseWheelHandler) ( UINT, WPARAM, LPARAM, BOOL& );

La línea del ejemplo declara una variable de nombre onMouseWheelHandler, que puede apuntar a cualquier miembro de la clase CCoConsola3D que reciba un UINT, un WPARAM, un LPARAM, una BOOL&, y devuela un LRESULT.

Esto en cuanto a la declaración. Ahora bien, para hacer que el puntero apunte a una determinada función miembro:

/*
 * Asumiendo que CCoConsola3D tiene un miembro llamado OnMouseWheelHandlerNotifyGUI que tenga
 * el encabezado dado por la declaración
 */
onMouseWheelHandler = &CCoConsola3D::OnMouseWheelHandlerNotifyGUI;

Y finalmente, para invocar a la función miembro seleccionada, dado que es una función miembro, necesitamos una instancia de CCoConsola3D y una sintaxis poco feliz:

// ¡Los paréntesis son necesarios!

// ...En otro método de CCoConsola3D:
(this->*onMouseWheelHandler)(uMsg, wParam, lParam, bHandled);

// En una clase cliente de CCoConsola3D:
(consola.*onMouseWheelHandler)(uMsg, wParam, lParam, bHandled);

Este mecanismo tiene muchas posibilidades: hay autores que lo consideran otra forma de polimorfismo, ya que nos permite cambiar dinámicamente el comportamiento de un objeto. Si lo comparamos con el mecanismo tradicional de herencia + funciones virtuales, éste tiene la ventaja de que no hay que destruir y crear de nuevo un objeto (de otra subclase) para cambiarle el comportamiento. Esto puede ser ventajoso si la destrucción y creación son operaciones temporal o espacialmente costosas.

Comments

Post a Comment

Popular posts from this blog

VB.NET: Raise base class events from a derived class

Apache Kafka - I - High level architecture and concepts

Upgrading Lodash from 3.x to 4.x