2012-04-10 8 views
6

Digamos que tengo un Handler de clase con algunas subclases como stringhandler, SomeTypeHandler, AnotherTypeHandler. El Handler de clase define un método "handle" como una interfaz común para todas las subclases. La lógica para "manejar" es por supuesto completamente diferente para los diferentes controladores.¿Cómo puedo pasar "Cualquier tipo de datos" a una función en C++

Entonces, lo que tengo que hacer es pasar un valor de cualquier cosa al método de manejo. Las clases específicas pueden lanzar el "cualquier cosa" al tipo que esperan.

Básicamente lo que necesito es algo así como el objeto de clase Java: D

Lo primero que probé fue una void*, pero al parecer no se puede hacer B* someB = dynamic_cast<B*>(theVoidPointer), por lo que no hay suerte.

Mi segunda idea fue utilizar boost::any. sin embargo, el requisito de usar boost :: any es que el valor debe ser copiable como cunstructable, que no es el caso para mis datos.

¿Alguna idea para que esto funcione?

Gracias

EDIT: Tenga en cuenta que sé que podría utilizar una clase somedata sin miembros en absoluto, y que mis datos sean subclases de eso, pero estoy en busca de un enfoque más genérico que no requiere de mí para hacer mi propia clase de contenedor.

+2

¿Estás seguro de que necesitas 'dynamic_cast', y no puedes usar' reinterpret_cast'? –

+1

¿Qué le parece usar plantillas? –

+0

Parece que la mayoría de sus opciones se describen aquí: http://stackoverflow.com/questions/913505/casting-void-pointers-depending-on-data-c – briantyler

Respuesta

1

bien, aquí es un enfoque simple usando cualquier impulso :: punteros para sostener a sus tipos de datos. Sin embargo, tenga en cuenta que boost :: any agrega un poco de disminución del rendimiento de los códigos generales (en la mayoría de los casos, negligencia). Considere usar boost :: spirit :: hold_any en su lugar, o anular * si no necesita seguridad tipo.

class Handler { 
public: 
    void handle(boost::any value) { 
     do_handle(value); 
    } 
private: 
    virtual void do_handle(boost::any& value) = 0; 
}; 

template<class T> 
class HandlerBase : public Handler { 
private: 
    void do_handle(boost::any& value) { 
     // here you should check if value holds type T*... 
     handle_type(*(boost::any_cast<T*>(value))); 
    } 

    void handle_type(const T& value) = 0; 
}; 

class StringHandler : HandlerBase<std::string> { 
private: 
    void handle_type(const std::string& value) { 
     // do stuff 
    } 
}; 

Ahora se puede escribir un montón de clases de controlador, que deriva de HandlerBase, sin suponer que los tipos manejados tienen una clase base común.

+0

Esta es la solución que utilicé, a excepción de la plantilla HandlerBase. Lo dejé fuera. Acabo de usar, dejé que los manipuladores específicos se lanzaran al tipo que necesitaban. Tan pronto como tenga múltiples manejadores para el mismo tipo de datos, consideraré poner la base de plantilla en el medio. ¡Gracias! –

-1

Usted puede hacer

B* someB = static_cast<B*>(theVoidPointer); 
+2

'static_cast' por favor. –

+0

@ R.MartinhoFernandes y BertR ¿Podría por favor eloborate sobre las diferencias entre reinterpretar, estático y dinámico? Pensé que la reinterpretación y la estática tenían algunos peligros. –

+0

@ W.Goeman Consulte esta pregunta anterior: http://stackoverflow.com/a/332086/46642 –

0

Usted necesita tener una clase base llamada DataObject o algo así. Todos sus tipos de datos (cadena, número, etc.) son sub clases de DataObject. La manija se define así:

void Handle(DataObject *dataObject); 

Esta es una manera mucho más segura de hacer lo que quiera. Para hacerlo aún mejor, DataObject incluso puede saber qué tipo de datos contiene. Luego, los manejadores pueden verificar que se les haya enviado el tipo correcto de datos.

+0

Esto es básicamente lo que agregué en mi edición. Esto parece una buena solución, pero estaba buscando un enfoque más genérico. Todavía lo mantengo en mi lista de opciones en caso de que las otras soluciones no funcionen. –

1

Por ejemplo, puede definir una clase base:

class BaseHandlerData { 
    ... 
}; 

Entonces derivan sus clases de datos específicos, que se espera por sus manipuladores:

class StringData: public BaseHandlerData { 
    ... 
}; 

class SomeData: public BaseHandlerData { 
    ... 
}; 

Entonces usted debe ser capaz de pasar una BaseHandlerData * argumento para el método de manejo, y utiliza algo como:

void handle(BaseHandlerData *data) { 
    StringData* stringData = dynamic_cast<StringData*>(...); 
    // handle your string data here ... 
} 

a caja fuerte eche a su tipo de datos esperado.

Gerald

+0

Esto es en detalle lo que dije brevemente en mi edición. Una buena solución, de hecho, pero prefiero no escribir la clase extra para esto. Prefiero tener esto como una utilidad básica (como boost :: any). –

Cuestiones relacionadas