2012-07-14 15 views
8

Tal vez estoy malentendido cómo funciona la herencia aquí, pero aquí está mi problema:C++ - typeid(), que se utiliza en la clase derivada no regresa tipo correcto

tengo una opción de clase, y una RoomOption clase que se deriva de eso. Tengo otra clase que contiene un vector de shared_ptrs. En main, agrego un RoomOption a ese vector. Luego, usando typeid() controlo el tipo, y me dice que es una Opción. Por lo que he leído, se supone que typeid devuelve tipos derivados, y shared_ptrs no causa slicing, por lo que no estoy seguro de lo que estoy haciendo mal.

Aquí está el código:

Room.h:

vector<shared_ptr<Option> > options; 
void addOption(shared_ptr<Option>); 
shared_ptr<Option> getOption(int); 

Room.cpp:

void Room::addOption(shared_ptr<Option> option){ 
    options.push_back(option); 
} 

shared_ptr<Option> Room::getOption(int i){ 
    return options[i]; 
} 

principal:

shared_ptr<Room> outside(new Room(0, "", "")); 
outside->addOption(shared_ptr<RoomOption>(new RoomOption(0, "Go inside", hallway))); 
cout<<typeid(player->getRoom()->getOption(0)).name().get()<<endl; 
//This line prints "class std::tr1::shared_ptr<class Option> 

Se me ocurre que tal vez cuando agregando u obteniendo una Opción, el Roo mOption se lanza como una Opción debido al tipo de devolución/argumento. Si ese es el caso, entonces, ¿cómo se supone que debo almacenar un vector de más de un tipo? ¿O estoy entendiendo todo mal? = \

+3

Está pidiendo el tipeo del puntero compartido. Intente obtener el tipo de elemento que contiene el puntero compartido. – Mat

+0

usa un dynamic_cast para verificar los tipos. Además de que su obtener el typeid de la shared_ptr – Paranaix

+0

Opciones de devoluciones * –

Respuesta

1

En primer lugar, yor obteniendo el tipeo del shared_ptr.

Luego debe usar dynamic_cast en lugar de typeid. Ej:

if (dynamic_cast<RoomOption*>(player->getRoom()->getOption(0).get()) != 0){ 
    cout << "Its a RoomOption!" << endl; 
} 
+0

¡Eso funcionó! Gracias por el ejemplo. Es extrañamente difícil encontrar un ejemplo simple de cómo verificar los tipos con el lanzamiento dinámico O.o –

+0

. Tenga en cuenta que un dynmic_cast se considera una operación muy costosa (ya que su código necesita buscar información RTTI). Por lo tanto, no deberías usarlo frecuentemente en códigos sensibles al tiempo. – Paranaix

+0

observado. Thanks =) –

1

El tipo de objeto al que apunta shared_ptr<Option> es parte de su valor, no su tipo. Por lo que esta línea de código se rompe:

cout<<typeid(player->getRoom()->getOption(0)).name()<<endl; 

Quiere esto:

cout<<typeid(player->getRoom()->getOption(0).get()).name()<<endl; 

O quizás:

cout<<typeid(*(player->getRoom()->getOption(0))).name()<<endl; 

Lo typeid no es te dice el tipo real de lo que ha pasado lo. Lo pasaste a shared_ptr<Option>. No mira dentro del objeto para ver lo que contiene.

+0

Gracias. Aún devuelve "Opción *" sin embargo. –

+0

Bien, ahora desreferencia ese puntero y ahí está. –

14

Los typeid funciona de manera diferente para polimórfico (para las clases que tienen al menos una función virtual) y los tipos no polimórficos:

  • Si el tipo es polimórfico, el typeinfo estructura correspondiente que representa se determina en tiempo de ejecución (el puntero vtable se usa comúnmente para ese propósito, pero este es un detalle de implementación)

  • Si el tipo no es polimórfico, los tipos correspondientes NFO estructura se determina en tiempo de compilación

En su caso, que en realidad tienen una clase polimórfica Option, pero shared_ptr<Option> complejo en sí no es polimórfico en absoluto. Básicamente es un contenedor que contiene un Option*.Hay absolutamente no relación de herencia entre Option y shared_ptr<Option>.

Si desea obtener el tipo de bienes, primero tiene que extraer el puntero real desde su recipiente usando Option* shared_ptr<Option>::get():

Option * myPtr = player->getRoom()->getOption(0).get(); 
cout << typeid(*myPtr).name(); << endl; 

O, alternativamente, (que es exactamente lo mismo):

Option& myPtr = *player->getRoom()->getOption(0); 
cout << typeid(myPtr).name(); << endl; 
+0

Quitaría la referencia al puntero vtable, es un detalle de implementación confuso. –

+0

¡Está bien, edité! –

+0

Nota: también puede simplemente usar 'operator *' para obtener una referencia a la 'Opción' subyacente directamente, en lugar de usar' get' y luego '' 'en el puntero. –

Cuestiones relacionadas