2008-12-09 24 views
115

Tengo una clase A y otra clase que hereda de ella, B. Estoy anulando una función que acepta un objeto de tipo A como parámetro, así que tengo que aceptar una A. Sin embargo, luego llamo a funciones que solo tiene B, por lo que quiero devolver falso y no proceder si el objeto pasado no es del tipo B.Encontrar el tipo de un objeto en C++

¿Cuál es la mejor manera de averiguar qué tipo el objeto pasó a mi función ¿es?

Respuesta

134

dynamic_cast debe hacer el truco

TYPE& dynamic_cast<TYPE&> (object); 
TYPE* dynamic_cast<TYPE*> (object); 

La palabra clave dynamic_cast arroja un dato de un puntero o una referencia tipo a otro, realizar una comprobación en tiempo de ejecución para garantizar la validez de la fundición.

Si intenta convertir el puntero a un tipo que no es un tipo de objeto real, el resultado del molde será NULO. Si intentas convertir para hacer referencia a un tipo que no es un tipo de objeto real, el elenco emitirá una excepción bad_cast.

Asegúrese de que haya al menos una función virtual en la clase Base para que dynamic_cast funcione.

+0

¿Qué quiere decir con que debe haber una función virtual en la clase Base para hacer que dynamic_cast funcione? Eso me parece importante, lo adivinaré. – GiCo

+0

OK lo encontré: la información de tipo de tiempo de ejecución (RTTI) está disponible solo para las clases que son polimórficas, lo que significa que tienen al menos un método virtual. dynamic_cast y typeid necesitan RTTI. – GiCo

+0

¿No lanza 'dynamic_cast' si no es convertible? ¿Hay alguna manera de hacerlo sin generar un tiro? – jww

19

Esto se llama RTTI, pero seguramente querrá reconsiderar su diseño aquí, porque encontrar el tipo y hacer cosas especiales basadas en él hace que su código sea más frágil.

+3

Es cierto. Desafortunadamente, estoy trabajando en un proyecto existente, así que no puedo cambiar el diseño ni nada de la clase A. – lemnisca

6

¿Está buscando dynamic_cast<B*>(pointer)?

2

Su descripción es un poco confusa.

En términos generales, aunque algunas implementaciones de C++ tienen mecanismos para ello, se supone que usted no debe preguntar sobre el tipo. En su lugar, se supone que debes hacer un dynamic_cast en el puntero a A. Lo que esto hará es que en el tiempo de ejecución, se verificará el contenido real del puntero a A. Si tiene una B, obtendrá su puntero a B. De lo contrario, obtendrá una excepción o nulo.

+1

Debe tenerse en cuenta que obtendrá una excepción * solamente * si realiza un molde de referencia que falla. es decir, dynamic_cast (t). Los moldes de puntero fallidos devuelven NULL. es decir, dynamic_cast (t) – AlfaZulu

+0

Sí, debería haber aclarado eso mejor. Gracias. Ojalá hubiera una palabra que describa en C tipos que son por referencia en lugar de por valor. – Uri

8

Probablemente incrustar en sus objetos de una "etiqueta" Identificación y lo utilizan para distinguir entre los objetos de la clase A y objetos de la clase B.

Sin embargo, esto muestra un defecto en el diseño. Idealmente, los métodos en B que A no tiene, deben ser parte de A, pero deben dejarse vacíos, y B los sobrescribe. Esto elimina el código específico de clase y está más en el espíritu de OOP.

2

Como otros indicaron, puede usar dynamic_cast. Pero generalmente el uso de dynamic_cast para descubrir el tipo de clase derivada en la que está trabajando indica el diseño incorrecto. Si está sobrescribiendo una función que toma el puntero de A como parámetro, entonces debería poder trabajar con los métodos/datos de la clase A en sí misma y no debería depender de los datos de la clase B. En su caso, en lugar de anularlos, si Asegúrese de que el método que está escribiendo funcionará solo con la clase B, luego debe escribir un nuevo método en la clase B.

0

Usar funciones sobrecargadas. No requiere dynamic_cast o incluso el apoyo de RTTI:

class A {}; 
class B : public A {}; 

class Foo { 
public: 
    void Bar(A& a) { 
     // do something 
    } 
    void Bar(B& b) { 
     Bar(static_cast<A&>(b)); 
     // do B specific stuff 
    } 
}; 
+0

Directamente de la pregunta original: "Más tarde llamo a funciones que solo B tiene", ¿cómo funcionaría la sobrecarga en ese caso? –

+0

Cuando llamas a Bar con una A, no pasa nada B. Cuando llamas a Bar con una B, se pueden invocar métodos que solo existen en B. ¿Lees la pregunta original? Bar es su "Estoy anulando una función que acepta un objeto de tipo A como parámetro" – jmucchiello

+6

Esto no funciona con polimorfismo dinámico, que sospecho que el cuestionario está utilizando. C++ no puede seleccionar una sobrecarga basada en la clase de tiempo de ejecución del parámetro, solo en función del tipo de tiempo de compilación. –

113

elenco dinámico es la mejor para su descripción del problema, pero sólo quiero añadir que se puede encontrar el tipo de clase con:

#include <typeinfo> 

... 
string s = typeid(YourClass).name() 
+3

Bueno si realmente no sabes cuál es tu objeto. La respuesta aceptada supone que sí. – unludo

+1

es tipo estándar de información? – xus

+4

@xus Sí. es parte de los encabezados std –

2

Porque tu clase no es polimórfica.Pruebe:

struct BaseClas { int base; virtual ~BaseClas(){} }; 
class Derived1 : public BaseClas { int derived1; }; 

Ahora BaseClas es polimórfico. Cambié la clase a struct porque los miembros de una estructura son públicos por defecto.

3

sólo para estar completa, construiré construir fuera de Robocide y señalan que typeid pueden utilizarse solos sin necesidad de utilizar el nombre():

#include <typeinfo> 
#include <iostream> 

using namespace std; 

class A { 
public: 
    virtual ~A() = default; // We're not polymorphic unless we 
          // have a virtual function. 
}; 
class B : public A { } ; 
class C : public A { } ; 

int 
main(int argc, char* argv[]) 
{ 
    B b; 
    A& a = b; 

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl; 
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl; 
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl; 
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl; 
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl; 
} 

Salida:

a is B: true 
a is C: false 
b is B: true 
b is A: false 
b is C: false 
+0

Buen ejemplo. ¡Gracias! – user

0

Si puede acceder a la biblioteca de impulso, tal vez type_id_with_cvr() función es lo que necesita, que puede provide data type without removing const, volatile, & and && modifiers. Aquí hay un ejemplo simple en C++ 11:

#include <iostream> 
#include <boost/type_index.hpp> 

int a; 
int& ff() 
{ 
    return a; 
} 

int main() { 
    ff() = 10; 
    using boost::typeindex::type_id_with_cvr; 
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl; 
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl; 
    std::cout << typeid(ff()).name() << std::endl; 
} 

Espero que esto sea útil.

Cuestiones relacionadas