lunes, 6 de julio de 2009

Nocturnal Initiative Events (1/2): Introducción

En la siguiente mini-serie de entradas estudiaremos la implementación de un sistema de Eventos en C++ que ha seguido el código de Nocturnal

Introducción Eventos

En este caso concreto, por evento me refiero a una implementación del patrón Observer: Observer Pattern (tamaño original)

El patrón Observer define una relación uno-muchos entre objetos, de forma que un objeto (el sujeto, subject) envía una notificación a uno o varios objetos (los observadores, observer) cuando ocurre un cambio de estado en el subject.

Para ello los observers han de registrarse previamente con el subject, para establecer que quieren ser notificados. Con este patrón evitamos que los observers tengan que realizar un pooling periódico para preguntarle al subject si ha cambiado su estado, y a la vez tenemos acceso al estado de los objetos observer, pues el código que se ejecuta cuando ocurre el cambio de estado es parte de los observers.

¿Cómo implementar ésto en C++? Para responder a ésto, antes debemos sentar algunas bases.

Punteros a función

En C/C++ una implementación parcial del patrón observer se consigue con punteros a función. Un puntero a función es una variable que almacena un puntero a la dirección de memoria donde empieza una función, de forma que al llamar a la variable con la sintaxis de una función, se ejecuta aquella a la que apunta

//Punteros a función en C/C++. 

//Puntero a función que recibe un entero como argumento y retorna un std::string
(std::string) (*MyFunctionPointer) ( int entero);

//definimos un par de funciones que cumplen la firma anterior
std::string Funcion1(int integer)
{
return "null";
}

std::string Funcion2(int integer)
{
std::ostringstream oss;
oss << integer;
return oss.Str();
}

//Declaramos una variable que almacenará el puntero a la función que queramos
MyFunctionPointer variableQueAlmacenaUnPunteroAFuncion;

//asignamos el valor de Function1 al puntero a función
variableQueAlmacenaUnPunteroAFuncion = Funcion1;

//prints "null"
std::cout << variableQueAlmacenaUnPunteroAFuncion (5) << std::endl;

//asignamos el valor de Function2 al puntero a función
variableQueAlmacenaUnPunteroAFuncion = Funcion2;

//prints "5"
std::cout << variableQueAlmacenaUnPunteroAFuncion (5) << std::endl;


Con los punteros a función sólo podemos almacenar una única función. Si quisieramos almacenar un conjunto de funciones, tendríamos que crear una lista de punteros.


Punteros a Método


El problema es que los punteros a función sólo pueden almacenar, bien funciones tradicionales C, o bien métodos estáticos de una clase. Esto sucede porque un método de una clase siempre tiene un parámetro oculto, el puntero this. Por ello en C++ existen los punteros a métodos:


class MiClase
{
public:
int MiMetodo(int entero1, int entero2){return entero1 + entero2;}
};

//Puntero a método de la clase MiClase
typedef int (MiClase::*MiPunteroAMetodo) (int entero1, int entero2);

Sin embargo una importante limitación es que para invocar un puntero a método, se requiere una instancia de la clase para la cual se ha definido el puntero a método:

MiPunteroAMetodo variableQueAlmacenaUnPunteroAMetodo = &MiClase::MiMetodo;
MiClase* miClase = new MiClase();
(miClase->*variableQueAlmacenaUnPunteroAMetodo)(5, 5);


Es decir, que necesitarmos guardar tanto la función método, como una instancia del objeto a la hora de implementar eventos en C++



Delegados y Eventos en C#


En C# tenemos la figura del delegate (delegado) que básicamente es lo mismo que un puntero a función y un puntero a miembro, ya que admite funciones y metodos de clase. A su vez permite "de serie", el registrar varias funciones al mismo delegate, de forma que cuando éste es llamado, se ejecutan todas las funciones registradas, y no sólo una como ocurre con los punteros a función o los punteros a método de C/C++ Un evento en C#, no es más que un delegado ya instanciado y con una sintaxis especial. Por ello los eventos en C# son una implementación de libro del patrón observer.



Para la siguiente entrada veremos cual ha sido la aproximación seguida en el código de Nocturnal para implementar eventos en C++.

4 Comentarios:

Anónimo dijo...
Este comentario ha sido eliminado por un administrador del blog.
Anónimo dijo...
Este comentario ha sido eliminado por un administrador del blog.
Anónimo dijo...

Shalom

I just wanted to say hi to everyone

See you

[URL=http://www.vpnclient.us][IMG]http://openvpn.net/archive/openvpn-users/2005-05/pngd55nFojmJX.png[/IMG][/URL]

Anónimo dijo...

hi everybody


Just saying hello while I read through the posts


hopefully this is just what im looking for looks like i have a lot to read.