Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Punterios A Funciones Miembro

Iniciado por ALRAZ, 26 de Septiembre de 2004, 09:42:17 PM

« anterior - próximo »

ALRAZ

 Alo genteeee  :lol:

Aquí les vengo con una duda interesante  :rolleyes:
O al menos espero que lo sea  :P


Verán, tengo una clase muy simpática:


class Algo
{
Public:
  void HacerAlgo ();
  void HacerOtraCosa ();
  void NoHacerNada ();
  void HacerComoQueHaceAlgo ();
};

Por poner un ejemplo

Ahora, lo que quiero hacer es, tener un puntero :huh: ... de hecho varios punteros
Cada uno de los cuales apunta a una función distinta de ESA clase.

Algo así como

 Puntero1 = MiClase.HacerOtraCosa;
 Puntero2 = MiClase.NoHacerNada;

Es posible? :blink:
(genial)  Cómo se hace?

(Sé cómo crear punteros a funciones, pero no punteros a funciones miembro de una clase (nooo)  )

Gracias de antemano  (ole)  

Sacrifai

 Yo no tengo mucha experiencia con punteros y no le veo sentido. Pero exactamente ¿para que lo quieres?

BeRSeRKeR

 Prueba esto:

class foo
{
public:
   void print(const char *name)
   {
       cout << "Hola, " << name << endl;
   }
};

void (foo::*pt2func) (const char *);

int main(int argc, char *argv[])
{
   pt2func = &foo::print;
   foo foo_inst;
   (foo_inst.*pt2func)("BeRSeRKeR");

   return 0;
}


Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

ALRAZ

 Veamos......


Es algo complicado de explicar para mi escaso talento....

Primero: es para un jueguillo mugriento que estoy intentando hacer.

Dentro del personaje principal (una clase), tengo un arreglo con varios Estados para ese personaje; Cada uno de estos estados ejecuta algún código común con los demás estados y una que otra cosa de código exclusivo.

Para hacerlo más .... mmmm... Productivo?

he pensado en dividir el código en pequeñas porciones de código, cada una de las cuales hace una cosa distinta con el personaje; ejemplo:
Avanzar, Detectar Colisión,  Revisar Cambio de Estado, Etc.

Todo esto se hace (o hacía) en una sola función, pero esto no puede consitnuar así, ya que hay estados como EstarDePïe que no requieren el código de Avanzar, y hacerlo con un Switch como que haría mucho revoltijo (Ya lo intenté XD y se repite mucho código :( ).

Actualmente ya he logrado crear un arreglo dinámico de punteros a función (nombre más raro  O_O ), donde cada casilla del arreglo apunta a cada una de estas pequeñas porciones de código ya mencionadas (Separada cada porción en su propia función), así, se pueden ejecutar en orden distinto o de plano no ejecutarse según lo que el Estado Actual requiera.
El problema con esto es que tengo que pasar un puntero a la clase actual a cada una de las funciones y eso no me parece muy eficiente; sería más fácil que la propia clase llamase a sus funciones miembro según fuese necesario


:huh:

uff...
espero que haya quedado bien explicado porque yo no me entendí nada  :P  

ALRAZ

 
Cita de: "BeRSeRKeR"Prueba esto:

[...]

    foo foo_inst;
   (foo_inst.*pt2func)("BeRSeRKeR");

[..]
mmm....

podrías explicar esas dos últimas líneas...?
particularmente la última  :)

ypor supuesto: Gracias

Lo he compilado y parece que ya funciona. A veri si me las arreglo yo solo pa' crear un arreglo de punteros a funciones miembrp  :lol:
Ya veremos que pasa  (ole)


Gracias de nuevo BeRSeRKeR

BeRSeRKeR

 
Cita de: "ALRAZ"podrías explicar esas dos últimas líneas...?
particularmente la última  :)
Pues no hay mucho que explicar. Es lo mismo que si estuvieras utilizando punteros a funciones normales excepto que para poder asignar la dirección de una función miembro de la clase tienes que crear una instancia de dicha clase. Si por ejemplo lo hicieras así:

pt2func("BeRSeRKeR");

el compilador te dirá que el puntero a la función no se encuentra en el ámbito de la clase. De ahí que tengas que crear una instancia de la clase y acceder al puntero desde ella:

foo foo_inst;
(foo_inst.*pt2func)("BeRSeRKeR");


Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

ethernet

 Te recomiendo que busques información sobre el pattern Functor y que visites www.function-pointer.org , tiene cosas muy interesantes además de código fuente.

PD: no sé si lo sabrás pero en el foro hay un pacto de caballeros de no usar imágenes en las firmas por razones más que obvias

Un saludo

shephiroth

 Muy buenas.

Veamos, no se si ayudará, pero bueno xDD.

En el proyecto que tuve que presentar tuve un problema bastante parecido. Aunque la mayoría del proyecto se encontraba bajo clases administradas, la clase que se encargaba de la comunicacion por red se encontraba bajo codigo c a secas. Por diversas razones (desconocimiento de las buenas artes, y falta de tiempo) algunas de las funciones de esas clases llamaban directamente a las funciones miembro de las clases de las que dependían.

Pongo un ejemplo grafico y quizás se me entienda mas:



class cones
{
llamaeventoa(){}

llamaeventob(){}
}
__gc class Aliole
{
cones * a;
eventoa(){}

eventob{}
}

Aliole * programa;



Vemos q el objeto programa es de la clase A. De este pende el objeto a que es de la clase cones, la cual necesita llamar a las funciones miembro de el objeto programa (y solo de este. en el proyecto habia 3 objetos del tipo programa, y ademas cada programa tenia 2 objetos cones, pero eso es otro tema)

Al final consegui un codigo bastante majo (aunque muy chapucero, mas tarde descubri un 'triger' (creo q se llama asi) q me dejaba crear un objeto de una clase administrada dentro de codigo no administrado), si ves el ejemplo se adapta a tus necesidades me avisas.

SALUDOS

ALRAZ

 Bueno, de lo de shephiroth no entendí ni una palabra  :blink: , pero con el código de BeRSeRKeR me fue más que suficiente para ponerme a hacer algo de prueba y error y conseguí tener un arreglo de punteros a funciones mu xulo  (ole)

Por lo de la imagen en la firma...
joer...
me lo acabo de leer en las reglas, no tenía ni la más remota idea  :(

Discupas por eso
y gracias por las respuestas tan oportunas  :lol:

Pogacha

 Hola:
vengo de un link que tu pusiste, me parece que lo que realmente te seria util es la virtualizacion de funciones, la idea seria:

class TPersonajeAI
{
 void IDLE(float tiempo);  
 {
 ... mover , detectar colisiones y resto.
     E->IDLE(tiempo);
}
 TEstado *E;
};

class TEstado
{
 virtual void IDLE(float Tiempo)
 TPersonajeAI *Padre
};

class TEnojado : public TEstado
{
 void IDLE(float Tiempo)
 {
     if(Tiempo>2.0) Padre->E=new TTranquilo;
    delete this;
 }
};

class TTanquilo : public TEstado
{
 void IDLE(float Tiempo)
 {
     if(Padre->LePegan() == true) Padre->E=new TEnojado;
    delete this;
 }
};


Esto no lo he hecho nunca, asi que puede estar mal.
Despues comentame si lo probaste.
Saludos

shephiroth

 Buenas.

No se muy bien si continuar por aqui o seguir en el otro pot, preo por alusiones quizás lo mejor sea que continue por aqui.

El manejo de funciones miembro, no me refería al ultimo codigo presentado. Es mas, ahi no veo alusiones a funciones de ningun tipo, solo fuenciones reescritas en clases hijas (por cierto, que eso de virtual no se que significa xDD).

Voy a poner un poco del codigo que estoy utilizando y quizás las cosas se vean mas claras:


int G2DTools::G2DT_CrearVentanaPrincipal(int width, int height, int izquierda, int derecha, LRESULT (__stdcall *func)(HWND, UINT, WPARAM, LPARAM))
{
...
G2DTools_v_main.WinProc = *func;
G2DTools_v_main.left = izquierda;
G2DTools_v_main.right = derecha;
G2DTools_v_main.width = width;
G2DTools_v_main.height = height;
G2DT_inicio_Main=true;
return G2DTools_v_ok;
}
LRESULT CALLBACK G2DTools::G2DT_MainWinProc( HWND hActual, UINT msg, WPARAM wParam, LPARAM lParam )
{
   switch( msg )
{
 case WM_CLOSE:
 {
  PostQuitMessage(0);
 }
 
       case WM_DESTROY:
 {
           PostQuitMessage(0);
 }
       break;
}
if (G2DTools_v_main.WinProc == G2DTools_null)
  return DefWindowProc( hActual, msg, wParam, lParam );
else return (*G2DTools_v_main.WinProc)( hActual, msg, wParam, lParam );
}


Como veis a esta funcion le puedo pasar una funcion global, en este caso esta preparado para que reciba la funcion de mensajes de windows. Ahora bien, quiero que el programador pueda utilizar en vez de una funcion global, una funcion miembro de una clase que el cree. Como se haría??

P.D: Game 2D Tools, no es un futuro motor, sino u conjunto de herramientas que sirvan al programador de 2d xDD

Pogacha

 Lo unico que se me ocurre en ese caso es crear una clase heredable:

class TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica
{
 public:
  virtual void FuncionLlamable(void);
}


Entonces el usuario deberia hacer:

class TMiPropiaClase : public TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica
{
 public:
  void FuncionLlamable(void);
}


y en vez de pasarle el puntero a la funcion (que tambien es posible) le pasas el puntero a la clase y listo

class TMiMotor
{
static TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica *f;
static void   Ejecutar_Funcion();
static void   Tomar_Clase(TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica *_f);
};

static TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica *MiMotor::f;

static void TMiMotor::Ejecutar_Funcion();
{
   f->FuncionLlamable();
}

static void TMiMotor::Tomar_Clase(TClase_Con_Un_Miembro_Llamable_Por_Una_Estatica *_f);
{
 f=_f;
}



Esta es la gran ventaja de la funcion Virtual, cuando hay una clase hija no requiere un cast, sino que llama a la funcion que es definida en el new.
En realidad vendria a ser como (yo lo he usado así sin problemas, aun que no estoy seguro del metodo verdadero):

Citarclass Padre{
funcion *f;
};

class Hija : public Padre{
  void mif();
  Padre() { f=mif; }
}
Saludos

shephiroth

 Muy buenas.

El codigo que expones es correcto, pero no me vale. Tu lo haces por medio de una clase, creando un objeto de esa clase dentro de la "clase del motor" y lo que haces es pasarle el objeto del que quiero invocar la funcion. Y eso no me por dos razones.

1) No conozco el nombre de la funcion que el usuario quiere invocar
2) Tampoco conozco que objeto la tendrá

Me parece que no me entendiste. Quiero darle LIBERTAD COMPLETA al usario para decirme que funcion tendré que ejecutar. Si viste la porcion de codigo que puse, quiero que las tools tengan un nucleo central de mensajes para hacer sus operaciones, y a la vez dar la opcion al usuario de que me pase la suya, y de llamarla en caso que sea necesario. Y en el caso de que no me pase ninguna lamar a la de windows por defecto (tal como se haría siempre). De esta forma le libero al usuario de tener que meterse con un tema tan pesado y complejo como es este (no se a vosotros pero a mi al principio me pareció terriblemente pesado y tedioso).

Un ejemplo (siempre se ven las cosas mas claras xDD):

class mijuego
{
void mijuego(){...}
void teclado(){...}
LRESULT mensajes(HWND hActual, UINT msg, WPARAM wParam, LPARAM lParam){...}
}


Ahora volviendo al codigo que puse


int G2DTools::G2DT_CrearVentanaPrincipal(int width, int height, int izquierda, int derecha, LRESULT (__stdcall *func)(HWND, UINT, WPARAM, LPARAM))


Como hago para que pueda recibir la funcion de la clase mijuego, de un objeto declarado tal que asi


mijuego * juego;
int res = G2DT_CrearVentanaPrincipal(640,480,0,0,&juego->mensajes);


Estaría eso bien?? debería de hacer algun apaño?? A eso me refiero >_<

Un saludo ^^

Pogacha

 Si te entendí, pero eso que quieres no se puede, mi idea era que si uno hace un juego con tu motor deberia hacer:

ElMotorDeshephiroth.h:
class TClaseBasePareElJuegoDelUsuarioProporcionadaPorElMotorDeshephiroth
{
 virtual void Mensajes();
};

ElMotorDelUsuario.h
#include "ElMotorDeshephiroth.h"
class TJuegoDelUsuarui : public TClaseBasePareElJuegoDelUsuarioProporcionadaPorElMotor
{
 void Mensajes();

};

Un puntero a funcion de una funcion miembro generico no existe.
Saludos

shephiroth

 Buenas.

Durante algun tiempo estuve pensando en hacer el "motor" como una clase que el usuario utilizase como intermediario entre el programa y el "motor".....estoy intentando hacerlo lo más sencillo posible, por lo que demomento, y a no ser que sea totalmente obligatorio, prefiero seguir como estoy. Un namespace que tenga todas las funciones y demas accesibles directamente, y a correr.

Si no es posible pues lo dejaré como lo tengo, que sea funcion global xDD

P.D: Ahora que salio el tema (y sorry por el offtopic), como hago para hacer funciones y/o variables privados en un namespace??






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.