elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Rompecabezas de Bitcoin, Medio millón USD en premios


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?  (Leído 6,344 veces)
digimikeh

Desconectado Desconectado

Mensajes: 191


Ver Perfil
alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
« en: 2 Abril 2022, 20:56 pm »

Buenas tardeS

Tengo 2 objetos:
ClaseA
ClaseB

ClaseA tiene una referencia a ClaseB en su cuerpo, pero ClaseB no debe tener referencia a ClaseA

Código
  1. //ClaseA
  2. class ClaseA {
  3.  
  4. private:
  5.    ClaseB* b {nullptr};
  6.  
  7. public:
  8.   void Alpha();
  9.  
  10. };
  11.  
  12.  
  13. //ClaseB
  14. class ClaseB {
  15. public:
  16.    void Beta();
  17. };


Lo que busco hacer es llamar desde ClaseA::Alpha() a ClaseB::Beta(), luego ClaseB::Beta() debe invocar a ClaseA::Alpha() de vuelta.


Código
  1. //ClaseA fuente
  2. void ClaseA::Alpha(){
  3.     //hacer algo
  4.     b->Beta();      //invoco a ClaseB::Beta()
  5.  
  6. }
  7.  
  8. //ClaseB fuente
  9. void ClaseB::Beta(){
  10.     //el hilo proveniente de ClaseA::Alpha pasa por aqui...
  11.     //hacer algo
  12.     //invocar de vuelta a ClaseA::Alpha() desde un principio...
  13. }


Pienso que puedo colocar algun parametro en ClaseB::Beta(), por ejemplo:

ClaseB::Beta(algun tipo o puntero a funcion miembro que apunte a la funcion anterior)

Entonces la invocacion seria:
Código
  1. b->Beta(&ClaseA::Alpha);

...cosa que al terminar Beta, ya sabe que funcion tiene que invocar despues, en este caso ClaseA::Alpha

Como se puede lograr esto?

gracias de antemano.



En línea

Dungeons & dragons;
dragons.Attack();
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
« Respuesta #1 en: 3 Abril 2022, 01:47 am »

A voz de pronto se me ocurre que alpha tuviera un flag que pueda activar beta (esto para evitar una recursión infinita). Si ese flag se activa a continuará con su ejecución, sino se repetirá desde el principio. No se C++, pero en C sería algo así:
Código
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3.  
  4. bool beta() {
  5.    static int i=0;
  6.    puts("Ejecuto beta");
  7.    i++;
  8.    return i<5;
  9. }
  10.  
  11. void alpha() {
  12. void alpha() {
  13.    do {
  14.        puts("Ejecuto alpha");
  15.    } while(beta());
  16.    puts("Fin de alpha");
  17. }
  18.    puts("Fin de alpha");
  19. }
  20.  
  21. int main() {
  22.    alpha();
  23. }

Si no quieres usar el do/while puedes usar el goto (si no le tienes manía)
Código
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3.  
  4. bool beta() {
  5.    static int i=0;
  6.    puts("Ejecuto beta");
  7.    i++;
  8.    return i<5;
  9. }
  10.  
  11. void alpha() {
  12.    inicio:
  13.    puts("Ejecuto alpha");
  14.    if(beta())
  15.        goto inicio;
  16.    puts("Fin de alpha");
  17. }
  18.  
  19. int main() {
  20.    alpha();
  21. }

O mediante setjmp/longjmp (no recomendado)
Código
  1. #include <stdio.h>
  2. #include <setjmp.h>
  3.  
  4. jmp_buf buf;
  5.  
  6. void beta() {
  7.    static int i=0;
  8.    puts("Ejecuto beta");
  9.    i++;
  10.    longjmp(buf, i);
  11. }
  12.  
  13. void alpha() {
  14.    if(setjmp(buf)<5) {
  15.        puts("Ejecuto alpha");
  16.        beta();
  17.    }
  18.    puts("Fin de alpha");
  19. }
  20.  
  21. int main() {
  22.    alpha();
  23. }


En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
« Respuesta #2 en: 3 Abril 2022, 17:35 pm »

Citar
Lo que busco hacer es llamar desde ClaseA::Alpha() a ClaseB::Beta(), luego ClaseB::Beta() debe invocar a ClaseA::Alpha() de vuelta.

Esto parece un error en el diseño de tu programa. No sólo por el bucle infinito que provocará, lo cual tiene solución simple (aunque no muy limpia) sino porque ese tipo de interdependencia casi nunca es bueno. Si es curiosidad lo que tienes, sí puedes pasar punteros a funciones miembro, pero teniendo en cuenta algunos detalles.

Las funciones miembro no static, como Alpha(), siempre se ejecutan en el contexto de un objeto concreto (el puntero this, que reciben como parámetro implícito). No puedes simplemente pasar el puntero a la función, sino que necesitas saber sobre qué objeto operar. Hay varias formas de hacerlo. Una simple que podrías probar es algo así:

Declaras Beta de esta manera

Código
  1. void Beta(void (ClaseA::*funcion)(void), ClaseA& o);

La invocas desde Alpha así:

Código
  1. b->Beta(&ClaseA::Alpha, *this);

Y dentro de Beta:

Código
  1. (o.*funcion)();

No es lo más limpio, pero simplifica el código (lo de evitar el bucle infinito te lo dejo. Hay muchas maneras de hacerlo). Aún así, reitero que te recomiendo que rediseñes el programa para no necesitar esto.
En línea

digimikeh

Desconectado Desconectado

Mensajes: 191


Ver Perfil
Re: alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
« Respuesta #3 en: 3 Abril 2022, 18:08 pm »

Gracias ambos!

El estilo C no deseo emplear mucho ya que este codigo es para continuar mi proyecto en Unreal Engine.. pero gracias de todas formas MAFUS porque me sirve de conocimiento general tu solucion.

RayR, si, efectivamente es un caso especial, estoy trabajando con corutinas, .. en este caso la clase B es una clase global, generalizada que se usa para muchos niveles, pero Clase A es una clase local que solo se utiliza para un nivel, podria haber hecho una interdependencia pero eso seria manchar ClaseB con informacion que no necesitaria mas tarde...

Lo solucione con std::function y std::bind  .. similar a lo que tu planteas.

El caso es que necesito hacerlo asi ya que es parte de una conversacion donde el hilo espera la senal del jugador (un boton) para pasar al siguiente comentario, luego con un parametro bool le digo a ClaseB que ese es el ultimo comentario para que no repita la funcion.


Saludos y gracias nuevamente.
En línea

Dungeons & dragons;
dragons.Attack();
Loretz

Desconectado Desconectado

Mensajes: 117


Ver Perfil
Re: alguna forma de pasar una funcion miembro como argumento a otro miembro de clase?
« Respuesta #4 en: 18 Abril 2022, 04:47 am »

Hola!
Acá puedes usar el concepto de "friends" (https://isocpp.org/wiki/faq/friends)

Una cosa espantosa puede ser algo así...

Código
  1. #include <iostream>
  2.  
  3. //ClaseB
  4. class ClaseB {
  5.    friend class ClaseA;
  6. public:
  7.    void Beta(class ClaseA* a);
  8. };
  9.  
  10. //ClaseA
  11. class ClaseA {
  12. private:
  13.    ClaseB* b;
  14.    bool hecho = false;
  15.    friend class ClaseB; // https://isocpp.org/wiki/faq/friends
  16.  
  17. public:
  18.    ClaseA() : b{ new ClaseB } {}
  19.    ~ClaseA() { delete b; }
  20.    void Alpha();
  21.  
  22. };
  23.  
  24.  
  25. //ClaseA fuente
  26. void ClaseA::Alpha() {
  27.    //hacer algo
  28.    if (hecho)
  29.        return;
  30.    b->Beta(this);      //invoco a ClaseB::Beta()
  31.    std::cout << "Alpha";
  32.    hecho = true;
  33. }
  34.  
  35. //ClaseB fuente
  36. void ClaseB::Beta(class ClaseA* a) {
  37.    //el hilo proveniente de ClaseA::Alpha pasa por aqui...
  38.    //hacer algo
  39.    //invocar de vuelta a ClaseA::Alpha() desde un principio...
  40.  
  41.    if (a->hecho)
  42.        return;
  43.    a->hecho = true;
  44.    std::cout << "Beta";
  45.    a->Alpha();
  46. }
  47.  
  48. // Lo que busco hacer es llamar desde ClaseA::Alpha() a ClaseB::Beta(), luego ClaseB::Beta() debe invocar a ClaseA::Alpha() de vuelta.
  49.  
  50. int main()
  51. {
  52.    ClaseA a;
  53.    a.Alpha();
  54.  
  55. }
« Última modificación: 18 Abril 2022, 05:11 am por Loretz » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines