| |
Páginas: [1] 2
|
 |
|
Autor
|
Tema: Punteros a funciones (Leído 926 veces)
|
SirLanceCC
Desconectado
Mensajes: 1.059
Equipo de Traducción
|
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.hclass 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.cppButton::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//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
Mensajes: 117
|
Buenas
Trataste sacandole el &?
Saludos, FreakMind
|
|
|
|
|
En línea
|
Connoisseurs of C semantics find C++ inferior to ++C 
|
|
|
|
|
|
Ragnarok
|
El problema de C++ es que te deja hacer de todo pero todo de formas muy feas  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: int (*f_ptr) (int p);
|
|
|
|
|
En línea
|
|
|
|
SirLanceCC
Desconectado
Mensajes: 1.059
Equipo de Traducción
|
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. //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
|
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... class xgToolBar:public xgWindow{ //prototipo de función que recibe el mensaje xgUInt xgOnToolBarNotify(xgWindow *xgParent,xgWParam wParam,xgLParam lParam); }; //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; } //prototipos de función "general" typedef int (xgEventTable::*pEvntClassFunc)(xgVoid*,xgWParam,xgLParam); typedef int (xgWindow::*pClassWndFunc)(xgVoid*,xgWParam,xgLParam); //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
Mensajes: 117
|
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
|
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... #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: #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
Mensajes: 1.059
Equipo de Traducción
|
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.hclass Conection{ public: int (* action)(); };luego... mm... Button.hclass 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.hclass Map : public Conection{ ... } //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
Mensajes: 117
|
Lo que yo decia es crear un objeto que contenga las funciones que necesitas por ejemplo 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
|
El problema de C++ es que te deja hacer de todo pero todo de formas muy feas  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: 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
|
|
|
|
ҒrεακΠιи∂
Desconectado
Mensajes: 117
|
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 #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; } #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
|
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: #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
|
|
|
|
|
| | |