elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.
 
Inicio Ayuda Ingresar Registrarse
06 Octubre 2008, 23:19  



+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderador: ®®)
| | |-+  Punteros a funciones
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] 2 Ir Abajo Imprimir
Autor Tema: Punteros a funciones  (Leído 926 veces)
SirLanceCC

Desconectado Desconectado

Mensajes: 1.059


Equipo de Traducción


Ver Perfil WWW
Punteros a funciones
« en: 15 Junio 2008, 15:11 »

Tengo la clase Button que al dar clic debe ejecutar una función que puede ser de cualquier clase. El problema es que no se como convertir el método de una clase a puntero.

Button.h
Código
class Button : public Object{
   public:
       Button();
       ~Button();
 
       //Establece la acción que ha de llevarse a cabo al clic
       void SetAction(int (*)());
 
   private:
       //puntero a la accion al clicar
       int (*action)();
};
 

Button.cpp
Código
Button::Button(){
   action = NULL;
}
 
//Esta funcion causa problemas... aunque parece que esto es correcto
void Button::SetAction(int (*function)()){
   action = function;
}
 
//Aqui ejecuta la accion
void Button::OnRelease(int button, int x, int y){
   //Si hay accion estblecida la ejecuta
   if(action != NULL) action();
}
 

main.cpp
Código
//Asi me dice que int no se puede convertir a int(*)()
//(Save() devuelve int por eso)
boton.SetAction(mapa.Save());
 
//Asi me dice "non-lvalue in unary `&'  "
boton.SetAction(&mapa.Save());
boton.SetAction(&(mapa.Save()) );
 
//Asi dice que es unknow type
boton.SetAction(&mapa.Save);
boton.SetAction(mapa.Save);
 

Waaaaa!! no se como hacerle!!! :-(
« Última modificación: 15 Junio 2008, 15:15 por SirLanceCC » En línea

ҒrεακΠιи∂

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Re: Punteros a funciones
« Respuesta #1 en: 15 Junio 2008, 17:06 »

Buenas

Trataste sacandole el &?

Saludos, FreakMind
En línea

Connoisseurs of C semantics find C++ inferior to ++C
SirLanceCC

Desconectado Desconectado

Mensajes: 1.059


Equipo de Traducción


Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #2 en: 15 Junio 2008, 17:41 »

Código
//Asi me dice que int no se puede convertir a int(*)()
//(Save() devuelve int por eso)
boton.SetAction(mapa.Save());
 
//Asi dice que es unknow type
boton.SetAction(mapa.Save);
En línea

Ragnarok
Moderador Global
*****
Desconectado Desconectado

Mensajes: 4.222


Ver Perfil
Re: Punteros a funciones
« Respuesta #3 en: 15 Junio 2008, 20:18 »

El problema de C++ es que te deja hacer de todo pero todo de formas muy feas :P

Prueba a hacer una clase "función" con tres métodos, añadir parámetro, ejecutar y recoger resultado. Luego haces subclases para definir cada función y las instancias para invocar a las funciones.

Si no puedes hacer lo que se hace en C y que es más feo todavía, que es poner un puntero a la función:

Código
int (*f_ptr) (int p);
En línea

No olvidéis leer las normas generales, además de las específicas de cada tablón.sgae, ladrones
SirLanceCC

Desconectado Desconectado

Mensajes: 1.059


Equipo de Traducción


Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #4 en: 15 Junio 2008, 23:28 »

No entendi.

Pero si ya tengo un puntero a función... lo que pasa es que quiero que referencie una función de cualquier clase y que la ejecute pero no hayo como.

EDITO:
Creo que descubri como hacerle pero debo definir que se reciban funciones de un solo tipo de clase.
Código
//Por ejemplo
void SetAction(int (Map::*)()); //Aqui sólo recibirá funciones de la clase Map que devuelvan int y no reciban parametros.
 
Además de eso todavía debo especificar un objeto.

To quiero que SetAction reciba funciones de cualquier clase y que puedan ser ejecutadas.
« Última modificación: 15 Junio 2008, 23:50 por SirLanceCC » En línea

Karman

Desconectado Desconectado

Mensajes: 230



Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #5 en: 16 Junio 2008, 05:03 »

te muestro un código de como lo implementé en mi framework... si necesitas más detalles puedes descargar el código... está en mi pag...

Código
class xgToolBar:public xgWindow{
  //prototipo de función que recibe el mensaje
  xgUInt xgOnToolBarNotify(xgWindow *xgParent,xgWParam wParam,xgLParam lParam);
};
 

Código
   //Seteamos el evento (va en el código del programa)
   notet=xgSetForcedEventProc(WM_NOTIFY,wCtrlId,xgToolBar::xgOnToolBarNotify);
 
  //donde usamos una macro para convertirlas a un formato "general"
  #define xgSetForcedEventProc(evntcode,ctrlid, pfun)\
 xgSetForcedET(evntcode,ctrlid,(pEvntClassFunc)&pfun,(xgVoid*)this)
 
  //enlistamos el evento...
  xgEventTable *xgSetForcedET(xgUInt evntcode,xgUInt CtrlId,pEvntClassFunc pfun,xgVoid *pClass){
     xgEventTable *fetf=new xgEventTable(evntcode,CtrlId,pfun,pClass);
     forcedEvntTable.Append(fetf);
     return fetf;
   }
 

Código
//prototipos de función "general"
typedef int (xgEventTable::*pEvntClassFunc)(xgVoid*,xgWParam,xgLParam);
typedef int (xgWindow::*pClassWndFunc)(xgVoid*,xgWParam,xgLParam);
 

Código
//recorremos la lista llamando a las funciones:
 
/*****************************************************************/
// Procesamiento forzado de eventos
/*****************************************************************/
xgInt xgWindow::xgForcedProcMsg(xgUInt uMsg, xgWParam wParam, xgLParam lParam){
 xgUInt ctrlId,bRet=0;xgEventTable *fep;
 xgWindow *pWClass=xgNull;
 pClassWndFunc pClassfun;
 xgList<xgEventTable*> fET(forcedEvntTable);
 fET.GotoFirst();
 while(!fET.End()){//recorremos la lista
   fep=fET.Next();
   if(fep->GetEventCode()==uMsg){
     ctrlId=fep->GetControlId();//esto sería el control del mensaje enviado por el W
     if(!ctrlId||(ctrlId&&ctrlId==(LOWORD(wParam)))){
       pWClass=(xgWindow*)(fep->GetPClass());//esta es la parte que te interesa...
       if(pWClass){//casteamos a una clase "padre"
         //casteamos a un tipo de función genérica (2º cast)
         pClassfun=(pClassWndFunc)(fep->GetClassFunction());
         //llamamos a la función
         bRet=(pWClass->*pClassfun)((xgVoid*)this,wParam,lParam);
       }
     }
   }
 }
 return bRet;
}
 

espero puedas entenderlo... es bastante engorroso, pero funciona muy bien...

S2
« Última modificación: 16 Junio 2008, 05:05 por Karman » En línea

ҒrεακΠιи∂

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Re: Punteros a funciones
« Respuesta #6 en: 16 Junio 2008, 06:49 »

Buenas

Podrias crear un objeto que se encargue de eso y sea la funcion en si. En ese caso para tener una definicion nueva solo hay que derivar de una clase base y listo.


Saludos, FreakMind
En línea

Connoisseurs of C semantics find C++ inferior to ++C
Karman

Desconectado Desconectado

Mensajes: 230



Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #7 en: 16 Junio 2008, 09:23 »

exacto... esa parte me olvidé de decirle... pero de todas formas... el método que definí anteriormente permite las dos cosas... acá encontré el código original en el que me base.. quizás sea más fácil de entender...

Código
#include <iostream>
 
using namespace std;
 
class clase;
typedef void (clase::*ptypefun)(int);
 
class clase{
 public:
   ptypefun classfun;
   clase(){};
};
 
class clase2 :public clase {
 public:
   void echo(int a){
     cout << "echo: " << a << endl;
   };
};
 
int main() {
 
 ptypefun pfun;
 
 clase uno;
 clase *dos = new clase;
 
 uno.classfun=static_cast<ptypefun>(&clase2::echo);
 dos->classfun=static_cast<ptypefun>(&clase2::echo);
 
 pfun=static_cast<ptypefun>(&clase2::echo);
 
 (uno.*pfun)(0);
 (dos->*pfun)(1);
 (uno.*uno.classfun)(3);
 (dos->*dos->classfun)(4);
 
 delete dos;
 cin.get();
}
 

y una pequeña variación:

Código
#include <iostream>
 
using namespace std;
 
class clase;
typedef void (clase::*ptypefun)(int);
 
class clase{
 protected:
   clase(ptypefun pfun):classfun(pfun){base=this;};
 public:
   clase(){};
   clase *GetBase(void) const {return base;};
   ptypefun classfun;
 private:
   static clase *base;
};
 
clase *clase::base=NULL;
 
class clase2 :public clase {
 public:
   clase2():clase(static_cast<ptypefun>(&clase2::echo)){};
   void echo(int a){
     printf("%d\n",this);
   };
   void pthis(void){printf("%d\n",this);}
   void setvar(int x){va=x;};
 private:
   int va;
};
 
int main() {
 clase2 dos;
 dos.setvar(156);
 dos.pthis();
 clase *cl1,*cl2;
 cl1=new clase;
 cl2=cl1->GetBase();
 delete cl1;
 (cl2->*cl2->classfun)(4);
 cin.get();
 return 0;
}
 

S2
« Última modificación: 16 Junio 2008, 09:33 por Karman » En línea

SirLanceCC

Desconectado Desconectado

Mensajes: 1.059


Equipo de Traducción


Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #8 en: 16 Junio 2008, 16:57 »

A ver que no estoy entendiendo mucho... pero... pffff digane si esto me serviría (o quizás es lo que tratan de decirme)

Hago una clase.. mmm algo asi
Conection.h
Código
class Conection{
 public:
   int (* action)();
};

luego... mm...
Button.h
Código
class Button : public Object, public Conection{
   public:
       Button();
       ~Button();
 
       //Establece la acción que ha de llevarse a cabo al clic
       void SetAction(int (Conection::*)());
 
   private:
       //puntero a la accion al clicar
       //int (*action)(); //ESTO YA NO
};

Entonces Map (la clase a la que pertenece la accion a realizar) tambien tendría que ser derivada de Conection.
Map.h
Código
class Map : public Conection{
...
}
 

Código
//luego en algun momento hago lo siguiente en Map
action = Save();
//luego en el main
boton.SetAction(mapa.action);
 


WAAAAA!!! NO SE YA ME HICE TODO BOLAS

pero porfavor diganme si lo que acabo de decir es coherente o de plano estoy perdido :-(
En línea

ҒrεακΠιи∂

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Re: Punteros a funciones
« Respuesta #9 en: 16 Junio 2008, 17:41 »

Lo que yo decia es crear un objeto que contenga las funciones que necesitas por ejemplo


Código
class Button : public Object, public Conection{
   public:
       Button();
       ~Button();
 
       int     Connection(void){
             return connection->Connection();
       }
       //Establece la acción que ha de llev arse a cabo al clic
       void SetAction(int (Conection::*)());
 
   private:
       Command       *command;
 
};

Entonces ahi podes tener toda una jerarquia de clases para crear distintas implementaciones del mismo metodo y ademas podes cambiarlo en run-time

Salu2, FreakMind
En línea

Connoisseurs of C semantics find C++ inferior to ++C
Ragnarok
Moderador Global
*****
Desconectado Desconectado

Mensajes: 4.222


Ver Perfil
Re: Punteros a funciones
« Respuesta #10 en: 16 Junio 2008, 19:55 »

El problema de C++ es que te deja hacer de todo pero todo de formas muy feas :P

Prueba a hacer una clase "función" con tres métodos, añadir parámetro, ejecutar y recoger resultado. Luego haces subclases para definir cada función y las instancias para invocar a las funciones.

Si no puedes hacer lo que se hace en C y que es más feo todavía, que es poner un puntero a la función:

Código
int (*f_ptr) (int p);

PD: sé que la respuesta queda rara, pero la redacté ayer, y por problemas de conexión no la he podido poner hasta hoy...
En línea

No olvidéis leer las normas generales, además de las específicas de cada tablón.sgae, ladrones
ҒrεακΠιи∂

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Re: Punteros a funciones
« Respuesta #11 en: 16 Junio 2008, 20:31 »

Buenas

Si no puedes hacer lo que se hace en C y que es más feo todavía, que es poner un puntero a la función:
No creo que usar punteros a funciones sea algo "feo". Es mas, ayuda muchisimo y acorta mucho el codigo.

Aca dejo dos ejemplos, uno usando punteros a funciones y otro no usandolo
Código
#include <stdio.h>
#include <stdlib.h>
 
#define PAUSE()     system("PAUSE")
#define CLR_SCR()   system("cls")
 
#define SALIR 5
 
void menu(void);
float sumar(float, float);
float restar(float, float);
float multiplicar(float, float);
float dividir(float, float);
void leerOperandos(float *, float *);
 
char *fname[] = {"suma", "resta", "multiplicacion", "division"};
float (*fcn)[](float, float) = {sumar,restar,multiplicar,dividir};
 
int main(void)
{
int opcion;
float a, b;
 
while(1){
menu();
scanf("%d",&opcion);
 
if(opcion < 1 || opcion > SALIR){
printf("Error. Opcion invalida\n");
PAUSE();
continue;
}
 
if(opcion == SALIR){
printf("Adios\n");
PAUSE();
exit(EXIT_FAILURE);
}
 
leerOperandos(&a, &b);
printf("El resultado de %s es %.2f\n", fname[opcion - 1], fcn[opcion - 1](a, b));
 
fflush(stdin);
PAUSE();
}
 
return 0;
}
 
void leerOperandos(float *a, float *b)
{
printf("Escribe Primer Numero: ");
scanf("%f",a);
printf("Escribe Segundo Numero: ");
scanf("%f",b);
 
return;
}
 
float sumar( float a, float b)
{
return a + b;
}
 
float restar( float a, float b)
{
return a - b;
}
 
float multiplicar( float a, float b)
{
return a * b;
}
 
float dividir( float a, float b)
{
if ( b )
return a / b;
printf("No se puede dividir por 0\n");
return 0;
}
 
void menu(void)
{
    CLR_SCR();
    printf("\n               *************MENU PRINCIPAL***************\n");
    printf("[1]. Sumar\n");
    printf("[2]. Restar\n");
    printf("[3]. Multiplicar\n");
    printf("[4]. Dividir\n");
    printf("[5]. Salir\n\n");
    printf("Ingrese su Opcion: ");
 
    return;
}

Código
#include <stdio.h>
#include <stdlib.h>
 
#define PAUSE()     system("PAUSE")
#define CLR_SCR()   system("cls")
 
#define SALIR 5
 
void menu(void);
float sumar(float, float);
float restar(float, float);
float multiplicar(float, float);
float dividir(float, float);
void leerOperandos(float *, float *);
 
char *fname[] = {"suma", "resta", "multiplicacion", "division"};
 
int main(void)
{
int opcion;
float a, b;
 
while(1){
menu();
scanf("%d",&opcion);
 
if(opcion < 1 || opcion > SALIR){
printf("Error. Opcion invalida\n");
PAUSE();
continue;
}
 
if(opcion == SALIR){
printf("Adios\n");
PAUSE();
exit(EXIT_SUCCESS);
}
 
leerOperandos(&a, &b);
switch(opcion){
                   case 1:
       printf("El resultado de %s es %.2f\n", fname[opcion - 1], sumar(a, b));
                   break;
                   case 2:
       printf("El resultado de %s es %.2f\n", fname[opcion - 1], restar(a, b));
                   break;
                   case 3:
       printf("El resultado de %s es %.2f\n", fname[opcion - 1], multiplicar(a, b));
                   break;
                   case 4:
       printf("El resultado de %s es %.2f\n", fname[opcion - 1], dividir(a, b));
                   break;
               }    
fflush(stdin);
PAUSE();
}
 
return EXIT_SUCCESS
}
 
void leerOperandos(float *a, float *b)
{
printf("Escribe Primer Numero: ");
scanf("%f",a);
printf("Escribe Segundo Numero: ");
scanf("%f",b);
 
return;
}
 
float sumar( float a, float b)
{
return a + b;
}
 
float restar( float a, float b)
{
return a - b;
}
 
float multiplicar( float a, float b)
{
return a * b;
}
 
float dividir( float a, float b)
{
if ( b )
return a / b;
printf("No se puede dividir por 0\n");
return 0;
}
 
void menu(void)
{
    CLR_SCR();
    printf("\n               *************MENU PRINCIPAL***************\n");
    printf("[1]. Sumar\n");
    printf("[2]. Restar\n");
    printf("[3]. Multiplicar\n");
    printf("[4]. Dividir\n");
    printf("[5]. Salir\n\n");
    printf("Ingrese su Opcion: ");
 
    return;
}

Salu2, FreakMind
« Última modificación: 16 Junio 2008, 21:23 por ҒrεακΠιи∂ » En línea

Connoisseurs of C semantics find C++ inferior to ++C
Karman

Desconectado Desconectado

Mensajes: 230



Ver Perfil WWW
Re: Punteros a funciones
« Respuesta #12 en: 16 Junio 2008, 20:40 »

no entendiste los ejemplos??? es re simple! pero tenes que tener en cuenta 1 factor fundamental... necesitas mantener  el puntero oculto this? o mejor dicho, a quien necesitas que apunte this!...

convirtiendo el código que te pasé a tus clases:

Código
#include <iostream>
 
using namespace std;
 
class Conection;
typedef void (Conection::*ptypefun)(int);
 
class Conection{
 public:
   Conection(){}
 
   void SetAction(ptypefun pfun){
     classfun=pfun;
   }
   void DoConection(int a){
     (this->*classfun)(a);
   }
 
   void SetAction2(void *pnclass,ptypefun pfun){
     classfun=pfun;
     pclass=pnclass;
   }
   void DoConection2(int a){
     (((Conection*)pclass)->*classfun)(a);
   }
 
 private:
   ptypefun classfun;
   void *pclass;
};
 
class Button:public Conection{
 public:
   Button(){};
   void OnEvent(int a){
     DoConection(a);
   };
};
 
class otraclase{
 public:
 otraclase(){}
 ~otraclase(){}
 void funcion(int z)//prototipo definido en connection
 {printf("funcion %d %X\n",z,this);}
};
 
int main() {
 Button dos;
 dos.SetAction((ptypefun)(&otraclase::funcion));
 dos.DoConection(100);
 
 otraclase x;
 dos.SetAction2((void *)&x,(ptypefun)(&otraclase::funcion));
 dos.DoConection2(100);
 
 cin.get();
 return 0;
}
 

la diferencia entre SetAction y SetAction2 es que en SetAction this apunta al objecto connection, mientras que en SetAction2 this apunta al objeto otraclase.
S2
« Última modificación: 16 Junio 2008, 20:43 por Karman » En línea

Ragnarok
Moderador Global
***