2009-11-11 15 views
6

Tengo una pequeña pregunta: ¿cómo puedo averiguar qué tipo es un puntero C++?Averiguar Tipo de C++ Void Pointer

que a menudo utilizan una pequeña función en mis programas de la consola para reunir información, que es como la siguiente:

void query(string what-to-ask, [insert datatype here] * input) 

Me gustaría crear una forma genérica, utilizando un puntero nulo, pero no puedo cin un puntero de vacío, entonces, ¿cómo puedo averiguar su tipo para poder lanzarlo?

+10

lo lanzas y cruzar los dedos. –

+0

Mire cómo funciona la función C nativa 'scanf()'. –

+0

Una pregunta: ¿quieres que el usuario pueda escribir CUALQUIER COSA y luego quieres analizarla en consecuencia? Digamos que escribe 14, luego quieres un "int", o 15.4 quieres un flotador? ¿Eso es? –

Respuesta

14

Ha sido un largo tiempo desde la última vez que codificado en C++, pero ...

no puede utilizar una Template?

+2

El OP está buscando RTTI, y eso no se aplica a void *. La plantilla es la respuesta. – Tanktalus

0

Si entiendo lo que está preguntando, la forma habitual de hacerlo es crear una clase de interfaz que admita query(string what-to-ask) y luego, en lugar de utilizar un puntero de vacío, simplemente pase un puntero a la interfaz. Luego puede llamar a query() en esa instancia.

9

No puede.

Sin embargo, una alternativa es eliminar los punteros vacíos, hacer que todo se derive de una clase base común y usar RTTI.

Un ejemplo:

class Base 
{ 
public: 
    virtual ~Base() {} 
}; 

class Foo : public Base { /* ... */ }; 

void SomeFunction(Base *obj) 
{ 
    Foo *p = dynamic_cast<Foo*>(obj); 
    if (p) 
    { 
     // This is of type Foo, do something with it... 
    } 
} 
+1

debería ser 'dynamic_cast ' –

+0

sí, eso es lo que quise decir. :-) corregido. – asveikau

+1

Tenga en cuenta que dynamic_cast puede ser muy lento, fácilmente un microsegundo cada uno, para cualquier jerarquía de clase más grande que trivial. – Crashworks

0

Nop. No puedes hacer esto. Si necesita algo como esto, sugiero Boost.Any.

2

void* es la forma todos los datos tienen. No puede "determinarlo" - es es, cualquier dato que tenga en el programa esvoid*! Sí, son fragmentos brutos de memoria, por diseño.

Usted podría programa todo su código con el uso de void* solamente. Afortunadamente, el lenguaje C proporciona conveniencia, lo que le permite manipular algunos datos como si no fueran void*. Pero si va a utilizar esta conveniencia, no debe convertirlos al void* y olvidarse de qué tipo eran.

+0

Todos los punteros están anulados *. La última vez que revisé, un char no está vacío *. Un int puede no ser nulo *. Un flotador no está vacío *. Pero char *, int * y float * son. – luiscubal

+1

Su punto es que todos los datos no son más que bytes en la memoria. Ints, chars, strings, etc. son solo interpretaciones. –

2

Su pregunta no es del todo claro para mí, pero tal vez lo que desea es sobrecargar query

void query(string what2ask, int* input) { 
    cout << what2ask; 
    cin >> *input; 
} 


void query(string what2ask, float* input) { 
    cout << what2ask; 
    cin >> *input; 
} 

int age; 
float sqrt2; 
query("How old are you?", &age); 
query("What's the square root of 2?", &sqrt2); 
+0

Más uno por simplicidad y claridad – Brad

0

Si controla el tipo de datos a sí mismo, probablemente hacer una clase/estructura que contiene una enumeración de todos los tipos de datos que te importan y los pasas. A continuación, puede consultar el puntero pasado para su tipo de datos, y luego emitir de manera apropiada.

IE (advertencia de código de pseudo -. Tratando esto como una estructura por ahora)

class MyDataType { 
    enum aDataType type; 
    void * myData; 
} 

void query(string whatToAsk, MyDataType * pdata) 
{ 
    switch (pdata.type) { 
     case integer: 
       int * workInt = (int *) pdata; 
       do whatever you want to to get the data 
       break; 
     case someFunkyObject: 
       someFunkyObject pob = (SomeFunkyObject *) pdata; 
       Do whatever you want with the data. 

     etc. 
    } 
} 
+1

Si estuviese etiquetando con enumeraciones (en lugar de usar RTTI), me inclinaría más a hacer que "myData" fuera una unión en lugar de un vacío * ... Menos punteros de esa manera, y sin dobleces. indirección Aunque es mucho más estilo C que C++. – asveikau

0

Se podía leer en un char * y luego analizar la cadena (char por char) para determinar si se trata de un int, float, cadena, lo que sea. La parte difícil es convertirla.

Por ejemplo:

para cada carácter en la cadena

si ('' carácter es a)

++ decimalcount

else if (carácter es una letra)

++ lettercount

final para el lazo

si decimalcount> 0 & & == 0 lettercount analizar a través de cada dígito de derecha a izquierda, multiplicando por potencias de 10 y añadiendo la suma

más si decimalcount == 1 & & lettercount == 0

aprender cómo flotadores están representados en binario y encontrar la función de otra persona para convertirlo para usted

más si lettercount> 0

es una cadena. ¡Hurra!

+0

Esto solo se aplica a cadenas de caracteres. Sería, por supuesto, condenado al fracaso en un 'void *' o cualquier otro puntero arbitrario reinterpretado como 'char *', ya que, por supuesto, cualquier tipo aritmético puede contener bytes que tengan el mismo patrón de bits que [inserte su personaje ASCII favorito aquí]. Aparte de la recuperación de datos/análisis forense, no tiene sentido tratar de adivinar juegos con punteros desreferenciados. No digo que lo seas, pero esa es una de las interpretaciones de la pregunta del OP, por lo que tiene un énfasis en –

4

En lugar de pasarle un void* que luego debe convertir al tipo correcto, probablemente debería utilizar una función de plantilla que se puede usar con todos los tipos que desee leer.

esta manera se obtiene el código de tipo seguro y no tiene a manera de escribir código especial para la mayoría de los tipos de entrada:

template<typename T> 
void query(const string &whattoask, T &input) { 
    cout << whattoask << endl; 
    cin >> input; 
    cout << endl; 
} 

int main() { 
    int i; 
    double d; 
    string s; 

    query("An integer: ", i); 
    query("Floating point: ", d); 
    query("A word: ", s); 
} 
+0

¡De acuerdo!2 para la plantilla, y eso es con lo que estoy yendo. ¡Gracias! – new123456