Ver la versión completa : ¿Se puede pasar métodos de clases como parámetros?
Puck2099
11/03/2008, 22:37
Buenas,
A ver, estoy haciendo pruebas y no sé si lo que intento es imposible o algo hago mal...
Mi intención es que a un método de un objeto de una clase A se le pase como parámetro un puntero a otro método de otro objeto de una clase B, de forma que desde A pueda llamar a dicho método en ejecución.
La idea de hacer esto sería encapsular lo máximo posible esas clases, de forma que desde A redefiniría unos métodos sin saber de qué tipo de objeto se trata B.
Concretando más, tengo un objeto de una clase Procesador y quisiera hacer lecturas de una memoria que estaría representada por otro objeto de clase Memoria. No me interesa que desde la clase Procesador se conozca de donde se va a leer, sino tener ahí un puntero que se pudiera inicializar en tiempo de ejecución y ya realizar las lecturas del objeto de clase Memoria.
De momento la única solución que se me ocurre para esto es hacer una clase base Procesador y luego de ésta crear una hija por herencia donde sí diría explícitamente que tirara de la clase Memoria.
¿Alguna idea?
^MiSaTo^
11/03/2008, 22:46
No entiendo muy bien lo que pretendes (estoy muerta) pero lo que quieres hacer es algo así: Procesador.metodo(Memoria.metodo());? Porque si es así en Java si se puede hacer y en C++ debería poderse hacer.
Si no es eso, siento entrometerme.
Supongo que te refieres a C++. En ese caso estoy casi seguro de que sí se puede, pero no me acuerdo muy bien de como.
^MiSaTo^
11/03/2008, 22:52
Supongo que te refieres a C++. En ese caso estoy casi seguro de que sí se puede, pero no me acuerdo muy bien de como.
Yo esque estoy enjavada pero me imagino que se hará más o menos igual porque son muy parecidos ;)
DarkDijkstra
11/03/2008, 22:57
Supongo que eso es a lo que te refieres...
http://www.newty.de/fpt/fpt.html
(y si, vamos, si que se puede ; )
romeroca
11/03/2008, 23:04
La wikipedia es tu amiga. :D
http://en.wikipedia.org/wiki/Function_pointers
Por cierto, ¿no tendrá nada que ver con uFenix verdad? ;)
Un saludete.
SpaVampyre
12/03/2008, 00:20
Revisa tu modelo entidad-relación porque eso que comentas me suena muy raro, no deberias poder pasar una referencia a un "trozo" de un objeto, ya que tu (el procesador)no debe saber nada mas ayá de la interfaz ofrecida por el objeto sobre el que quieres trabajar;
Creo que deberias pasarle al Procesador el objeto memoria como parametro, entero y sobre el solicitar el metodo, porque tratar de ejecutar un metodo de un objeto accediendo directamente a la memoria en la que está este viola toda la orientación a objetos; si lo que quieres es tener distintos tipos de memoria, crea una clase "padre" Memoria que tenga un metodo Abstracto "leer" y varias clases "hijo" en las que cada una define el metodo "leer" como le corresponda, de este modo puedes pasar un objeto memoria al procesador y este solicitar el metodo "leer" sin conocer el tipo de memoria.
Si lo que quieres es que el procesador le diga de algun modo a la memoria de donde debe leer, deberas pasarle esta dirección como parametro al metodo leer, o tener un metodo en la clase memoria que permita fijar la dirección de memoria a partir de la que se va a leer (esto sería un "set" y no son del todo correctos tampoco, pero pueden pasar).
Si no es eso lo que quieres o no me he explicado bien explicame con un poco mas de detalle lo que quieres hacer, en lenguaje natural, y te veo que diseño de clases y Entidad-Relación se puede hacer.
P.D. Tambien puedes crearte una clase "padre" abstracta "Sitio desde el que se lee" con unos metodos abstractos de lectura, y de ella heredar la clase memoria, la clase "otro sitio desde el que se lee pero no es una memoria" etc... y pasar esta clase "Sitio desde el que se lee" a procesador llamando así al metodo leer (que habras definido en cada subclase del mismo) sin importarte de que subclase se trata, ya que te aseguras una minima interfaz común gracias a la clase Abstracta.
Puck2099
12/03/2008, 00:56
No, no me refiero a punteros a funciones (eso lo controlo bastante), aunque es parecido...
Ahora es muy tarde y he cerrado el portatil (donde llevo todo el TFC), pero mañana os pongo un esbozo de código de lo que me refiero, aunque creo que SpaVampyre es el que más se ha acercado a lo que decía (se ve que me explico bastante mal :angel1:).
Hasta mañana :brindis:
Supongo que eso es a lo que te refieres...
http://www.newty.de/fpt/fpt.html
(y si, vamos, si que se puede ; )
uhmm pues a mi esto si que me vale, porque el tema es que estoy usando una funcion C# que usa un handler y espera un puntero a una funcion, y resulta que la funcion es un metodo de una clase.
Como dicen, viola un poco la orientacion a objetos, pero si necesitas mezclar algo de c++ con c# al estilo esto que cuento no hay otra manera :)
Aiken
Pues estoy con romeroca, lo que describe Puck parecen punteros a funciones porque aunque sean métodos de clases, también son funciones. Siguiendo el ejemplo de Misato, sería algo así como procesador.metodo(memoria.metodo) (es decir, ¡sin paréntesis interiores!) y no puede hacerse en Java aunque sí en C++ y Python. Viola todo el paradigma de orientación a objetos y si quieres hacer algo más académico la solución es una jerarquía de clases como la descrita por SpaVampyre.
Los punteros a funciones (o su equivalente en otros lenguajes) no violan otras metodologías de programación más modernas que la OOP, así que si con punteros a funciones te va bien y no te preocupa no tener OOP pura, adelante :)
No. No se puede pasar ningún tipo de dirección de un método de una instancia de una clase para ser llamado desde otro lado. Rompe con todas las reglas del paradigma de programación con objetos. Solo puedes hacer eso con métodos estáticos de una clase, pero piensa que los miembros estáticos no pertenece a ninguna instancia concreta de la clase, así que desde un método estático no puedes acceder a ningún atributo a menos que sea estático también.
< - >
Una forma de arreglar este problema por ejemplo es usando polimorfismo en este sentido:
#include <iostream>
//CLASE ENCAPSULADORA
class Func {
public:
virtual void *Exec(void *ptr) = 0;
};
//UNA DE LAS CLASES QUE SOBRECARGA
class MyClass: public Func{
public:
void *Exec(void *instance)
{std::cout << "Hello! Soy MyClass!" << std::endl;}
};
class MyClass2: public Func{
public:
void *Exec(void *instance)
{std::cout << "Internet Serious bussines" << std::endl;}
};
class MyClass3: public Func{
public:
void *Exec(void *instance)
{std::cout << "Blah blah blah" << std::endl;}
};
int main() {
Func* execs[3];
execs[0] = new MyClass();
execs[1] = new MyClass2();
execs[2] = new MyClass3();
for(int i = 0; i < 3; i++) execs[i]->Exec(NULL);
}
Si no, en caso de ser tu clase singleton (tiene una única instancia), siempre podéis crear una función estática que lo único que haga es obtener la instancia estática y llamar al método de la instancia. Así, al ser static el método puedes obtener su dirección y llamarlo usando el puntero.
NoobLuck
12/03/2008, 13:04
Tal vez lo que propones no sea la solución más elegante al problema.
Yo creo que en vez de pasar el método de una clase deberías pasar un puntero a la instancia de la clase y posteriormente usar ese puntero para llamar al método que deseas.
Además así queda más clara la dependencia entre los objetos.
O tal vez haya otra solución que se adapte más a lo que buscas.
Para demostrar que ambos métodos funcionan y es solo cuestión de gustos, pongo ambas soluciones en Python. OOP es muy bonita cuando la explican en las clases y tal, pero si las cosas tienen que funcionar bien, rápido, ocupar poco y ayer, la OOP puede ser la mejor solución... o no.
Procesador.ejecuta() toma como parámetro un método de otra clase, y Procesador.ejecutaOOP() un objeto de la clase y después llama al método.
class Memoria:
def escribe(self, datos):
self.datos = datos
def lee(self):
return self.datos
class Procesador:
def ejecuta(self, lector):
print 'Ejecutando datos: ' + lector()
def ejecutaOOP(self, memoria):
print 'Ejecutando datos (OOP): ' + memoria.lee()
m = Memoria()
m.escribe('estos son los datos')
p = Procesador()
p.ejecuta(m.lee)
p.ejecutaOOP(m)
OOP clásica y jerarquizada tal como la explican varios foreros:
class Memoria:
datos = None
def lee(self):
return self.datos
class RAM(Memoria):
def escribe(self, datos):
self.datos = datos
class ROM(Memoria):
def __init__(self):
self.datos = 'Datos fijos'
class Procesador:
def ejecuta(self, memoria):
print 'Ejecutando datos: ' + memoria.lee()
rom = ROM()
ram = RAM()
ram.escribe('Datos modificables')
p = Procesador()
p.ejecuta(ram)
p.ejecuta(rom)
SpaVampyre
12/03/2008, 14:30
Si la POO no es la mejor solución no se usa, pero usarla mal es un error.
Hacer un puntero a un metodo es un error grave de diseño, uiza el error sea haber planeado un diseño con objetos cuando no es lo mas recomendable.
Hecha un vistazo a PAtrones de diseño en POO, en concreto al patrón Visitor, seguramente ahí encuentres una solución.
Hacer un puntero a un metodo es un error grave de diseño
No, es un atentado contra la OOP que solo es una metodología de programación y no de las más modernas. No tiene por qué ser un error de diseño si lo que buscas es máxima velocidad y mínimo impacto en memoria (vamos, si estás programando un emulador o una máquina virtual fenix) Claro que también esta afirmación puede ser discutible o directamente falsa con algunos compiladores.
A lo mejor pasar una función como parámetro no te hará aprobar el examen de la asignatura "ingeniería del software", pero si es la única solución que se te ocurre hoy cenas en casa. Y además en diseños basados en eventos y varios threads (WinForms de Microsoft, por ejemplo) es la única alternativa si no quieres volverte medio loco. Y en lenguajes con tipado débil (la mitad de .Net, los interpretados y algunos de JVM) es incluso más legible. Oye, pero yo solo soy un ingeniero práctico que resuelve problemas.
Lo que tú buscas son punteros a funciones miembro (member function pointers)y si se puede hacer.
Ahora, eso es distinto a que sean la solución a tu problema.
Los punteros a métodos hay que usarlos con un cuidado escandaloso, porque estan increiblemente limitados en C++. Entre otras cosas porque para usarlos necesitas una instancia de la clase a la que pertenece el miembro para poder realizar la llamada al mismo. Son un coñazo, no los uses.
Si quieres saber TODO (y lo digo en serio) sobre ellos, mira este artículo:
http://www.codeproject.com/KB/cpp/FastDelegate.aspx
Nocturnal, el código que ha liberado Insominiac, los usa parcialmente para generar un patron Evento/Delegado en C++, por si lo quieres ver.
Respecto a tu problema, lo mejor que puedes hacer es definir un interface común y crear clases que lo implementen:
#define INTERFACE class
#define BYTE char
INTERFACE IMemoryPointer
{
public:
BYTE* virtual GetMemoryAddress() = 0;
};
class Procesador
{
private:
IMemoryPointer * _memoryPtr;
public:
Procesador(IMemoryPointer memPtr):_memoryPtr (memPtr) {}
void DoRead()
{
BYTE* address = _memoryPtr.GetMemoryAddress();
// do more stuff
}
};
No se si esto te valdría de solución.
Si me permites hacer de adivino, me parece que pensaste en punteros a método igual que piensas en punteros a función (defino una especificación para el método de función y así puedo cambiar la función que hace el trabajo en tiempo de ejecución). El problema es que por un lado los punteros a funciones miembor no son exactamente eso, y en segundo caso hay mejores formas de implementar ese comportamiento den C++, como por ejemplo un functor.
http://en.wikipedia.org/wiki/Functor
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.