Punteros a funciones con clases, ¿se puede?.

25/05/2004 - 18:23 por Tomás | Informe spam
Hola a todos:

Tengo una clase de propósito general a la que quiero enviar la dirección de
una función, (lo que en "C" es un puntero a función), para que se ejecuten
unas rutinas según el ciclo de trabajo.

El problema es que con clases no se como se puede hacer.

Agradecería cualquier ayuda.

Ejemplo de construcción:

// -Archivo1.cpp/h
class ClaseGeneral
{
public:
HRESULT FuncionA(??? pFuncion(int));
}

HRESULT ClaseGeneral::FuncionA(??? *pFuncion(int))
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
pFuncion???
// Hace mas cosas
return;
}


// -Archivo2.cpp/h
class ClaseA::public ClaseDialogo
{
public:
BOOL Funcion1();
BOOL Funcion2(int);

ClaseGeneral m_ClaseGeneral;
};


BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA(??? Funcion2(int))
// Hace mas cosas
return TRUE;
}

BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}

Gracias por anticipado.

Un saludo.

Tomás

Preguntas similare

Leer las respuestas

#1 Isidro Muñoz
25/05/2004 - 19:52 | Informe spam
Hola,
La principal diferencia de hacer esto en C y en C++ es el parametro this,
En C tu guardas un puntero a una función y cuando la llamas es un call
normal.
En C++ introduce en la pila el puntero this, o sea, la instancia creada y
luego hace el call, para poder acceder a los miembrso de la clase.

Borland en C++ Builder creo la palabra __closure para poder llamar a
funciones de clases, haciendo esto cuando se llama a la función introduce el
this en la pila. Creo que en Visual C++ 7.00 hay algo tambien para esto.

Una cosa que puedes hacer es declarar la función como static dentro de la
clase general, y se comportará como una función global.

Ahora mismo no lo recuerdo pero puedes mirar los punteros a funciones
miembrso en C++.

Pero si usas C++ puedes solvertarlo de otra forma, Si quieres llamar a una
función y pasarle un puntero a una función de una clase, evidentemente lo
que quieres es poder llamarlo desde diferentes clases porque si no no tiene
sentido.

Create una clase padre con la función Función2 como virtual pura, luego
haces que ClaseA herede de ella y todas las clases que quieras llamar a su
función tambien las haces que hereden de esta.

Cuando llames a m_ClaseGeneral le pases la clase padre, y luego desde
m_ClaseGeneral llamas al método Funcion2.

Quedaría así:

class ClaseGeneral
{
public:
HRESULT FuncionA(ClasePadre *p);
}

HRESULT ClaseGeneral::FuncionA(ClasePadre *p)
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
p->Funcion2();
// Hace mas cosas
return;
}

class ClasePadre
{
public:
virtual BOOL Funcion2(int)=0;
}

// -Archivo2.cpp/h
class ClaseA::public ClaseDialogo: public ClasePadre
{
public:
BOOL Funcion1();
BOOL Funcion2(int);

ClaseGeneral m_ClaseGeneral;
};


BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA(this)
// Hace mas cosas
return TRUE;
}
BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}


Tambien puedes hacer otra cosa, llamar a la función de proposito general
desde Funcion1 guardar los datos en un miembro de la clase A y luego llamar
a Funcion2 desde Clase A

HRESULT ClaseGeneral::FuncionA()
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
//Guardas los datos en un miembro de Clase General, por ejemplo aux;
aux=5;
// Hace mas cosas
return;
}

BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA()
m_ClaseGenerla.aux <- Aqui tengo el valor creado en FuncionA
// Hace mas cosas
return TRUE;
}
BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}


Saludos,
Isidro.

"Tomás" escribió en el mensaje
news:%
Hola a todos:

Tengo una clase de propósito general a la que quiero enviar la dirección


de
una función, (lo que en "C" es un puntero a función), para que se ejecuten
unas rutinas según el ciclo de trabajo.

El problema es que con clases no se como se puede hacer.

Agradecería cualquier ayuda.

Ejemplo de construcción:

// -Archivo1.cpp/h
class ClaseGeneral
{
public:
HRESULT FuncionA(??? pFuncion(int));
}

HRESULT ClaseGeneral::FuncionA(??? *pFuncion(int))
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
pFuncion???
// Hace mas cosas
return;
}


// -Archivo2.cpp/h
class ClaseA::public ClaseDialogo
{
public:
BOOL Funcion1();
BOOL Funcion2(int);

ClaseGeneral m_ClaseGeneral;
};


BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA(??? Funcion2(int))
// Hace mas cosas
return TRUE;
}

BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}

Gracias por anticipado.

Un saludo.

Tomás


Respuesta Responder a este mensaje
#2 Tomás
26/05/2004 - 08:15 | Informe spam
Gracias Isidro.

Tus soluciones son acertadas pero no resuelve la lógica que necesito
resolver.

Yo estoy buscando poder llamar desde mis distintas clases de dialogo
(Dialogo1, Dialogo2, Dialogo3, etc) a una función de propósito general
(class ClaseGeneral) que me hace una lectura distinta a una base de datos
dependiendo del dialogo desde donde se llama y el resultado obtenido,
(previo tratamiento especial), enviarlo a un archivo de texto formateado de
acuerdo con la clase de dialogo que se este utilizando.

Ejemplo:
class ClaseGeneral
{
public:
HRESULT FuncionA((parámetros para leer la base de datos), ???
pFuncion(int));
}

HRESULT ClaseGeneral::FuncionA((parámetros para leer la base de datos),???
*pFuncion(int))
{
// Hace cosas ...
While(EOF) {
...
pFuncion??? // Llama a la pFuncion del dialogo que se ha enviado a esta
función.
...
}
// Hace mas cosas
return;
}

// Para cada dialogo (1,2,3,...).
class CDialogX::public ClaseDialogo
{
public:
BOOL FuncionX();
BOOL FuncionZ(int);

ClaseGeneral m_ClaseGeneral;
};

BOOL CDialogX::FuncionX()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA((parámetros para leer la base de datos),???
FuncionZ(int))
// Hace mas cosas
return TRUE;
}

BOOL CDialogX::FuncionZ(int)
{
// Hace el tratamiento especifico de la información de acuerdo con el
dialogo que se este usando.
return TRUE
}

Espero que así quede mas claro.

Un saludo.

Tomás.

"Isidro Muñoz" <imunoz@()daipro.net> escribió en el mensaje
news:
Hola,
La principal diferencia de hacer esto en C y en C++ es el parametro this,
En C tu guardas un puntero a una función y cuando la llamas es un call
normal.
En C++ introduce en la pila el puntero this, o sea, la instancia creada y
luego hace el call, para poder acceder a los miembrso de la clase.

Borland en C++ Builder creo la palabra __closure para poder llamar a
funciones de clases, haciendo esto cuando se llama a la función introduce


el
this en la pila. Creo que en Visual C++ 7.00 hay algo tambien para esto.

Una cosa que puedes hacer es declarar la función como static dentro de la
clase general, y se comportará como una función global.

Ahora mismo no lo recuerdo pero puedes mirar los punteros a funciones
miembrso en C++.

Pero si usas C++ puedes solvertarlo de otra forma, Si quieres llamar a una
función y pasarle un puntero a una función de una clase, evidentemente lo
que quieres es poder llamarlo desde diferentes clases porque si no no


tiene
sentido.

Create una clase padre con la función Función2 como virtual pura, luego
haces que ClaseA herede de ella y todas las clases que quieras llamar a su
función tambien las haces que hereden de esta.

Cuando llames a m_ClaseGeneral le pases la clase padre, y luego desde
m_ClaseGeneral llamas al método Funcion2.

Quedaría así:

class ClaseGeneral
{
public:
HRESULT FuncionA(ClasePadre *p);
}

HRESULT ClaseGeneral::FuncionA(ClasePadre *p)
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
p->Funcion2();
// Hace mas cosas
return;
}

class ClasePadre
{
public:
virtual BOOL Funcion2(int)=0;
}

// -Archivo2.cpp/h
class ClaseA::public ClaseDialogo: public ClasePadre
{
public:
BOOL Funcion1();
BOOL Funcion2(int);

ClaseGeneral m_ClaseGeneral;
};


BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA(this)
// Hace mas cosas
return TRUE;
}
BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}


Tambien puedes hacer otra cosa, llamar a la función de proposito general
desde Funcion1 guardar los datos en un miembro de la clase A y luego


llamar
a Funcion2 desde Clase A

HRESULT ClaseGeneral::FuncionA()
{
// Hace cosas ...
// Llama a la Funcion2 de la ClaseA
//Guardas los datos en un miembro de Clase General, por ejemplo aux;
aux=5;
// Hace mas cosas
return;
}

BOOL ClaseA::Funcion1()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA()
m_ClaseGenerla.aux <- Aqui tengo el valor creado en FuncionA
// Hace mas cosas
return TRUE;
}
BOOL ClaseA::Funcion2(int)
{
// Hace cosas
return TRUE
}


Saludos,
Isidro.

"Tomás" escribió en el mensaje
news:%
> Hola a todos:
>
> Tengo una clase de propósito general a la que quiero enviar la dirección
de
> una función, (lo que en "C" es un puntero a función), para que se


ejecuten
> unas rutinas según el ciclo de trabajo.
>
> El problema es que con clases no se como se puede hacer.
>
> Agradecería cualquier ayuda.
>
> Ejemplo de construcción:
>
> // -Archivo1.cpp/h
> class ClaseGeneral
> {
> public:
> HRESULT FuncionA(??? pFuncion(int));
> }
>
> HRESULT ClaseGeneral::FuncionA(??? *pFuncion(int))
> {
> // Hace cosas ...
> // Llama a la Funcion2 de la ClaseA
> pFuncion???
> // Hace mas cosas
> return;
> }
>
>
> // -Archivo2.cpp/h
> class ClaseA::public ClaseDialogo
> {
> public:
> BOOL Funcion1();
> BOOL Funcion2(int);
>
> ClaseGeneral m_ClaseGeneral;
> };
>
>
> BOOL ClaseA::Funcion1()
> {
> // Hace cosas
> // Llama a la FuncionA de la ClaseGeneral.
> m_ClaseGeneral.FuncionA(??? Funcion2(int))
> // Hace mas cosas
> return TRUE;
> }
>
> BOOL ClaseA::Funcion2(int)
> {
> // Hace cosas
> return TRUE
> }
>
> Gracias por anticipado.
>
> Un saludo.
>
> Tomás
>
>


Respuesta Responder a este mensaje
#3 Isidro Muñoz
26/05/2004 - 10:38 | Informe spam
Hola Tomas,

Que yo sepa C++ no soporta punteros a funciones miembros de clases, tienen
punteros a miembros de clase pero eso es que tu tienes que tener en una
Clase varias funciones del mismo tipo como por ejemplo:

class a
{
public:
int funcion1(int);
int funcion2(int);
int funcion3(int);
...
int funcion4(int);

}

Puedes crear un puntero a las funciones de la clase a, y que pueda cambiar,
pero solo dentro de la misma clase,
int (a::*pf)(int); // Se declara como un puntero miembro a una funcion de
la clase a de tipo int.
pf = a::funcion3; // apunta a la funcion3
pf = a::funcion2; // apunta a la funcion2
pf = a::funcion1;
// si quiero utilizar es a traves de una instanacia de la clase
a aux;
a *paux2;
pf=a::funcion3;
aux.*pf(3);
pf = a::funcion1;
paux->*pf(3);

Pero esto no te resuelve tu problema, Borland en C++ Builder creo la palabra
restringida __closure para esto, evidentemente si la creo es proque en C++
estandar no se puede hacer.

Si todas las funciones que llama la clasegeneral de los distintos dialogos
se llaman igual FuncionZ lo tienes que hacer como te indique, clasepadre con
la FuncionZ, todos los dialogos heredarian de la clase padre, y luego
pasarle un puntero al padre que sería el this y finalmente llamar desde
clase padre a traves del this.

Todas las llamadas a instanacias de clases se hacen a traves de su this, o
del puntero a la clase, cuando llamas a ClaseGeneral tienes que pasarle la
instancia porque sino luego no sabe donde llamar, a no ser como te indique
sea static, pero si es static no puedes acceder a los miembros de una
instancia.

Ahora bien si el problema que tienes es que los Dialog no tienen porque
tener todos la misma funcion FuncionZ, o sea, que cada dialog pueda tener
distintas funciones para este proposito y dependiendo de algo pasarle una y
otra, entonces ya se complica esto más.

Pero si ese es el caso lo que tienes que hacer es crear un tipo int estado
dento de cada Dialog, y cuando llames a ClaseGeneral inicializar el estado,
luego clase General llamará a FuncionZ y esta en funcion del estado que
tenga el dialog hace una caso y otra

class ClasePadre
{
int FuncionZ(int) = 0;
}

class Dialog2:: public ClasePadre
{
int estado;
int Funcion1();
int FuncionZ(int);
}

class Dialog3:: public ClasePadre
{
int estado;
int Funcion1();
int FuncionZ(int);
int FuncionZ1();
int FuncionZ2();
}
class Dialog4:: public ClasePadre
{
int estado;
int Funcion1();
int FuncionZ(int);
}

int ClaseGeneral::FuncionA("datos...",ClasePadre *p)
{
while(EOF)
p->FuncionZ(x);
}


int Dialog2::Funcion1()
{
estado=5;
m_ClaseGeneral.FuncionA("busca los que sea",this);
}

int Dialog2::FuncionZ(int i)
{
int result;
switch(estado)
{
case 0: result=FuncionZ1(i); break;
case 1: result=FuncionZ2(i); break;
...
etc
}
return result;
}

Donde FuncionZ1, y FuncionZ2 son me´todos privados.

Saludos.
Isidro.

"Tomás" escribió en el mensaje
news:
Gracias Isidro.

Tus soluciones son acertadas pero no resuelve la lógica que necesito
resolver.

Yo estoy buscando poder llamar desde mis distintas clases de dialogo
(Dialogo1, Dialogo2, Dialogo3, etc) a una función de propósito general
(class ClaseGeneral) que me hace una lectura distinta a una base de datos
dependiendo del dialogo desde donde se llama y el resultado obtenido,
(previo tratamiento especial), enviarlo a un archivo de texto formateado


de
acuerdo con la clase de dialogo que se este utilizando.

Ejemplo:
class ClaseGeneral
{
public:
HRESULT FuncionA((parámetros para leer la base de datos), ???
pFuncion(int));
}

HRESULT ClaseGeneral::FuncionA((parámetros para leer la base de datos),???
*pFuncion(int))
{
// Hace cosas ...
While(EOF) {
...
pFuncion??? // Llama a la pFuncion del dialogo que se ha enviado a esta
función.
...
}
// Hace mas cosas
return;
}

// Para cada dialogo (1,2,3,...).
class CDialogX::public ClaseDialogo
{
public:
BOOL FuncionX();
BOOL FuncionZ(int);

ClaseGeneral m_ClaseGeneral;
};

BOOL CDialogX::FuncionX()
{
// Hace cosas
// Llama a la FuncionA de la ClaseGeneral.
m_ClaseGeneral.FuncionA((parámetros para leer la base de datos),???
FuncionZ(int))
// Hace mas cosas
return TRUE;
}

BOOL CDialogX::FuncionZ(int)
{
// Hace el tratamiento especifico de la información de acuerdo con el
dialogo que se este usando.
return TRUE
}

Espero que así quede mas claro.

Un saludo.

Tomás.
Respuesta Responder a este mensaje
#4 Rodrigo Corral [MVP]
26/05/2004 - 10:55 | Informe spam
Creo que estas modelando mal el tema, no estas pensnado orientado a objetos.
Yo utilizaria un aproximación basada en el patrón Strategy.

La idea es encapsular el algoritmo a utilizar por cada un de los dialogos en
una clase. Seria algo como esto (pseudocodigo ojo!!!)

abstract class Alg
{
public void Algoritmo() = 0; //
}

class AlgA : public Alg
{
public void Algortimo(.)
{
//Implementación A
}
}

class AlgB : public Alg
{
public void Algortimo(.)
{
//Implementación B
}
}

Cada uno de tus dialogos sabra que clase utilizar, bien por que la instancie
o por que se la pases en el constructor, por ejemplo;

BOOL CDialogX::FuncionX()
{
Alg a = new AlgB();
a->Alg(.);
}

O si has pasado en el constructor la clase a utilizar y la has almacenado
en m_Alg de tipo Alg, algo de este estilo

CDialog::CDialog(Alg alg)
{
m_Alg = alg;
}

BOOL CDialogX::FuncionX()
{
m_Alg->Alg(.);
}

Rodrigo Corral González [MVP]

microsoft.public.es.vc FAQ
http://vcfaq.europe.webmatrixhosting.net
Respuesta Responder a este mensaje
#5 Tomás
26/05/2004 - 17:11 | Informe spam
Gracias Isidro y Rodrigo.

No tengo mucho margen de maniobra porque utilizo unas cosas heredadas, pero
a ver si puedo cambiar un poco la lógica e implantar alguna de las ideas que
me habéis dado.

Un saludo.

Tomás.

"Rodrigo Corral [MVP]" escribió en el mensaje
news:
Creo que estas modelando mal el tema, no estas pensnado orientado a


objetos.
Yo utilizaria un aproximación basada en el patrón Strategy.

La idea es encapsular el algoritmo a utilizar por cada un de los dialogos


en
una clase. Seria algo como esto (pseudocodigo ojo!!!)

abstract class Alg
{
public void Algoritmo() = 0; //
}

class AlgA : public Alg
{
public void Algortimo(.)
{
//Implementación A
}
}

class AlgB : public Alg
{
public void Algortimo(.)
{
//Implementación B
}
}

Cada uno de tus dialogos sabra que clase utilizar, bien por que la


instancie
o por que se la pases en el constructor, por ejemplo;

BOOL CDialogX::FuncionX()
{
Alg a = new AlgB();
a->Alg(.);
}

O si has pasado en el constructor la clase a utilizar y la has almacenado
en m_Alg de tipo Alg, algo de este estilo

CDialog::CDialog(Alg alg)
{
m_Alg = alg;
}

BOOL CDialogX::FuncionX()
{
m_Alg->Alg(.);
}

Rodrigo Corral González [MVP]

microsoft.public.es.vc FAQ
http://vcfaq.europe.webmatrixhosting.net


email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida