2010-11-03 16 views
14

Ha pasado un tiempo desde que tuve que escribir el código C++ y me siento un poco estúpido.Cómo selecciono una clase padre como clase secundaria

class Parent 
{ 
    ... 
}; 

class Child : public Parent 
{ 
    ... 
}; 

class Factory 
{ 
    static Parent GetThing() { Child c; return c; } 
}; 

int main() 
{ 
    Parent p = Factory::GetThing(); 
    Child c1 = p; // Fails with "Cannot convert 'Parent' to 'Child'" 
    Child c2 = (Child)p; // Fails with "Could not find a match for 'TCardReadMessage::TCardReadMessage(TCageMessage)'" 
} 

Sé que esto se supone que es simple, pero no estoy seguro de lo que estoy haciendo mal: código que es similar a, pero no es exactamente, el código de abajo que he escrito.

+0

No entiendo lo que Factory está haciendo. Parece que está devolviendo una variable local. Es ese objeto valido? – John

+4

@John: está devolviendo una copia de un objeto local. La devolución es por valor, por lo que no importa si el original muere después (y por supuesto, sí). No hay nada de malo en eso, aparte de que no es apropiado para una función de fábrica ... –

+0

Sí, el método GetThing en la clase Factory devuelve una variable local. Que aparentemente no hará lo que quiero. Debo usar punteros en su lugar. Al menos según las respuestas a continuación. – Mykroft

Respuesta

15

Un objeto Parent devuelto por el valor no puede contener información Child. Hay que trabajar con punteros, punteros inteligentes de preferencia, por lo que no tiene que limpiar después de ti mismo:

#include <memory> 

class Factory 
{ 
    // ... 

public: 

    static std::auto_ptr<Parent> GetThing() 
    { 
     return std::auto_ptr<Parent>(new Child()); 
    } 
}; 

int main() 
{ 
    std::auto_ptr<Parent> p = Factory::GetThing(); 
    if (Child* c = dynamic_cast<Child*>(p.get())) 
    { 
     // do Child specific stuff 
    } 
} 
+1

GetThing debe [devolver un auto_ptr] (http://stackoverflow.com/q/1837665/54262) (o similar). Luego puede asignar el valor de retorno directamente a un puntero inteligente, o usar el método de liberación de auto_ptr. –

+0

GetThing() debe estar en público. – bjskishore123

+0

En primer lugar, 'Child * c' en la expresión moldeada. Te perdiste el '*'. En segundo lugar, un downcasting 'dynamic_cast' requiere un tipo polimórfico. Los tipos de OP no son conocidos por ser polimórficos. Si 'Parent' no es polimórfico, tu código no se compilará. – AnT

1

No se puede, en realidad. Su fábrica ha devuelto un objeto Parent, que se construyó a partir del objeto Childc [*]. La parte Niño ya se ha eliminado, ya que se devuelve a la función main. No hay forma de recuperarlo.

Quizás desee utilizar punteros?

[*] Excepto que, Child c(); declara una función, no define un objeto. Pero este no es tu código real, y supongo que tu clase real tiene parámetros de constructor.

+0

Sí, lo siento, es una suposición correcta sobre el constructor. – Mykroft

-1

No puede moldear los objetos reales, pero puede lanzar punteros a los objetos.

Para la emisión del código de uso punteros como esto:

Child* c = reinterpret_cast<Child*>(p); 
+2

Yo recomendaría 'dynamic_cast' –

+0

Estoy de acuerdo con max - reinterpret_cast podría verse como" cast de último recurso ":) – Flexo

+0

¿Por qué usaría dynamic_cast o reinterpret_cast en lugar de simplemente decir' Child * c = (child *) p; ' – Mykroft

0

No se puede convertir un objeto de la clase padre a hijo tipo de clase. Un objeto de la clase padre es ... bueno, un objeto de la clase padre. La clase secundaria amplía la clase primaria, lo que significa que un objeto de la clase principal generalmente es "más pequeño" que un objeto de clase secundaria. Por esta razón, el casting (o la reinterpretación) de la clase padre como clase infantil no tiene sentido en absoluto.

Explique qué es lo que está tratando de hacer. Sin una explicación, tu pregunta simplemente no tiene sentido.

2

Creo que el problema no está en la forma en que intentas hacer el reparto, sino en el motivo por el que quieres lanzarlo en primer lugar. El código no tiene sentido, incluso si fue sinápticamente válido. Estás tratando de convertir una "fruta" en una "manzana" en un contexto en el que es fácil demostrar que en realidad no tienes una manzana. Los moldes dinámicos y similares solo son útiles cuando tienes un puntero a una "fruta" que tienes razones para pensar que también es una "manzana".

+0

Este código es solo un ejemplo para mostrar las partes relevantes de cómo se combina mi código. No es mi código de producción real. – Mykroft

0

Probablemente no desee ser elegido aquí. Si Parent tiene algún método abstracto, simplemente llámelos y la clase derivada los manejará automáticamente.

Hay momentos en los que se vinculan elementos relativamente no relacionados para almacenarlos en una colección, ya sea tipos de variantes o situaciones donde diferentes estados conducen a objetos no relacionados que se manejan de forma diferente, y en esas ocasiones es posible que desee .

Por cierto, estoy bastante sorprendido de que no haya obtenido un error de compilación en GetThing() porque ha declarado c como una función por lo que no está devolviendo un elemento primario.

Además, dicho sea de paso, si copia por el valor que se "corte" de este modo:

Child c; 
Parent p(c); 
Child & c2 = dynamic_cast< Child& >(p); // throws bad_cast 
0

Consulte el siguiente fragmento de código:

Child* c = dynamic_cast<Child*>(parentObject); 

donde, parentObject es de tipo Parent*

Asegúrese de que el "parentObject" sea en realidad del tipo "Child", de lo contrario, comportamiento indefinido.

Consulte para More Info

Cuestiones relacionadas