2008-10-28 13 views
5

Digamos que tengo una clase Base y varias Clases derivadas. ¿Hay alguna manera de convertir un objeto a una de las clases derivadas sin la necesidad de escribir algo como esto:C++ casting programmatically: ¿se puede hacer?


string typename = typeid(*object).name(); 
if(typename == "Derived1") { 
    Derived1 *d1 = static_cast< Derived1*>(object); 
} 
else if(typename == "Derived2") { 
    Derived2 *d2 = static_cast < Derived2*>(object); 
} 
... 
else { 
    ... 
} 

Respuesta

22

No.

Lea sobre el polimorfismo. Casi todas las situaciones de "lanzamiento dinámico" son un ejemplo de polimorfismo que lucha por implementarse.

Cualquier decisión que esté tomando en el lanzamiento dinámico ya se ha realizado. Simplemente delegue el trabajo real a las subclases.

Olvidaste la parte más importante de tu ejemplo. El trabajo útil, polimórfico.

string typename = typeid(*object).name(); 
if(typename == "Derived1") { 
    Derived1 *d1 = static_cast< Derived1*>(object); 
    d1->doSomethingUseful(); 
} 
else if(typename == "Derived2") { 
    Derived2 *d2 = static_cast < Derived2*>(object); 
    d2->doSomethingUseful(); 
} 
... 
else { 
    ... 
} 

Si cada subclase implementa doSomethingUseful, todo es mucho más simple. Y polimórfico.

object->doSomethingUseful(); 
+0

Este es un detalle minucioso, pero quería mencionarlo. Quiere decir d1-> y d2-> en lugar de d1. y d2. ,¿derecho? Como los tipos de puntero usan el operador de flecha para llegar a las funciones de miembro. :) –

3

por lo general, esto es un signo de un mal diseño. ¿Por qué necesitas hacer esto? Podría ser posible rediseñar para que esto no sea necesario.

1

Su ejemplo no se transferirá, porque no se especifica el formato exacto del nombre(). Puede intentar una sucesión de dynamic_cast s. Dynamic_cast devuelve un puntero nulo si lo convierte al tipo incorrecto. Sin embargo, si está haciendo un tipo de cambio como este, hay algo mal con su diseño.

9

Puede usar dynamic_cast y probar NULL, pero tendría fuertemente considere refaccionar el código.

Si necesita un manejo específico de las subclases, Template Method puede ser útil, pero sin saber lo que está tratando de lograr, es solo una vaga suposición.

2

¿Qué intentas lograr, exactamente? En mi experiencia, este tipo de cosas son un signo de mal diseño. Vuelva a evaluar su jerarquía de clases, porque el objetivo del diseño orientado a objetos es hacer que cosas como esta sean innecesarias.

5
Derived1* d1 = dynamic_cast< Derived1* >(object); 
if (d1 == NULL) 
{ 
    Derived2* d2 = dynamic_cast< Derived2* >(object); 
    //etc 
} 

tengo los métodos siguientes en mi tipo SmartPointer, simulando C# 'es' y 'como':

template< class Y > bool is() const throw() 
    {return !null() && dynamic_cast< Y* >(ptr) != NULL;} 
template< class Y > Y* as() const throw() 
    {return null() ? NULL : dynamic_cast< Y* >(ptr);} 
4

Usted puede hacer esto utilizando dynamic_cast, por ejemplo:

if (Derived1* d1 = dynamic_cast<Derived1*>(object)) { 
    // object points to a Derived1 
    d1->foo(); 
} 
else if (Derived2* d2 = dynamic_cast<Derived2*>(object)) { 
    // object points to a Derived2 
    d2->bar(); 
} 
else { 
    // etc. 
} 

Pero, como otros han dicho, un código como este puede indicar un mal diseño, y generalmente debe usar virtual functions para implementar un comportamiento polimórfico.

1

creo dynamic_cast es el camino a seguir, pero yo particularmente no creo que esto es un mal diseño para todas las condiciones posibles porque el objeto a ser moldeado puede ser algo proporcionado por algún módulo de terceros. Digamos que el objeto fue creado por un complemento que el autor de la aplicación no conoce. Y ese complemento particular puede crear el objeto de tipo Derived1 (que es la versión antigua) o el objeto de tipo Derived2 (la nueva versión).Tal vez la interfaz del complemento no fue diseñada para hacer cosas específicas de la versión, solo crea el objeto, por lo que la aplicación debe hacer este tipo de comprobación para garantizar la correcta conversión/ejecución. Después de esto, podemos llamar de forma segura a object.doSomethingUsefulThatDoesNotExistInDerived1();