2010-11-03 7 views
14

Cela fait longtemps que je n'ai pas écrit de code C++ et je me sens un peu bête. J'ai écrit le code qui est similaire à, mais pas exactement, le code ci-dessous:Comment convertir une classe parente en classe enfant

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)'" 
} 

Je sais que cela est censé être simple mais je ne sais pas ce que je fais mal.

+0

Je ne comprends pas ce que Factory fait. Il semble que cela renvoie une variable locale. Cet objet est-il valide? – John

+4

@John: renvoie une copie d'un objet local. Le retour est en valeur, donc peu importe si l'original meurt après (et bien sûr, il le fait). Rien à redire à cela, sinon que ce n'est pas approprié pour une fonction d'usine ... –

+0

Oui, la méthode GetThing de la classe Factory retourne une variable locale. Ce qui apparemment ne fera pas ce que je veux. Je devrais utiliser des pointeurs à la place. Au moins selon les réponses ci-dessous. – Mykroft

Répondre

15

Un objet Parent retourné par la valeur ne peut pas contenir éventuellement aucune information Child. Vous devez travailler avec des pointeurs, pointeurs de préférence à puce, de sorte que vous ne devez pas nettoyer après vous:

#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 devrait [retourner un auto_ptr] (http://stackoverflow.com/q/1837665/54262) (ou similaire). Vous pouvez ensuite affecter la valeur de retour directement dans un pointeur intelligent ou utiliser la méthode de publication de auto_ptr. –

+0

GetThing() doit être en public. – bjskishore123

+0

Premièrement, 'Child * c' dans l'expression de transtypage. Vous avez manqué le '*'. Deuxièmement, un downcasting 'dynamic_cast' nécessite un type polymorphe. Les types d'OP ne sont pas connus pour être polymorphes. Si 'Parent' n'est pas polymorphe, votre code ne sera pas compilé. – AnT

1

Vous ne pouvez pas, vraiment. Votre usine a renvoyé un objet , qui a été construit à partir de l'objet Childc [*]. La partie enfant a déjà été coupée, car elle est retournée à la fonction main. Il n'y a aucun moyen de le récupérer.

Peut-être que vous voulez utiliser des pointeurs?

[*] Sauf que Child c(); déclare une fonction, il ne définit pas d'objet. Mais ce n'est pas votre vrai code, et je suppose que votre vraie classe a des paramètres constructeurs.

+0

Ouais désolé c'est une supposition correcte sur le constructeur. – Mykroft

-1

Vous ne pouvez pas diffuser les objets réels, mais vous pouvez diffuser des pointeurs sur les objets.

Pour lancer le code d'utilisation de pointeurs comme ceci:

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

Je recommanderais 'dynamic_cast' –

+0

D'accord avec max - reinterpret_cast pourrait être vu comme" casting de dernier recours ":) – Flexo

+0

Pourquoi devrais-je utiliser dynamic_cast ou reinterpret_cast au lieu de simplement dire" Child * c = (enfant *) p; ' – Mykroft

0

Vous ne pouvez pas lancer un objet de classe parente type de classe enfant. Un objet de la classe parent est ... eh bien, un objet de la classe parent. La classe enfant étend la classe parent, ce qui signifie qu'un objet de la classe parente est généralement "plus petit" qu'un objet de la classe enfant. Pour cette raison, lancer (ou réinterpréter) la classe parent en tant que classe enfant n'a aucun sens. Expliquez ce que vous essayez de faire. Sans une explication, votre question n'a tout simplement aucun sens.

2

Je pense que le problème n'est pas la façon dont vous essayez de faire le casting, mais avec la raison pour laquelle vous voulez lancer en premier lieu. Le code n'a aucun sens - même s'il était syntaxiquement valide. Vous essayez de jeter un «fruit» dans une «pomme» dans un contexte où il est facile de prouver que vous n'avez pas de pomme. Les lancements dynamiques et similaires ne sont utiles que lorsque vous avez un pointeur vers un "fruit" que vous avez des raisons de chose est aussi une "pomme".

+0

Ce code est juste un exemple pour montrer les parties pertinentes de la façon dont mon code est mis en place. Ce n'est pas mon code de production actuel. – Mykroft

0

Vous ne voulez probablement pas être ici du tout. Si Parent a des méthodes abstraites, vous les appelez simplement et la classe dérivée les traitera correctement.

Il est parfois nécessaire de lier des éléments relativement indépendants afin de les stocker dans une collection, que ce soit des types de variantes ou des situations où des états différents conduisent à des objets différents qui sont traités différemment. . Soit dit en passant, je suis assez surpris que vous n'ayez pas eu une erreur de compilation sur GetThing() parce que vous avez déclaré c en tant que fonction pour ne pas retourner un parent.

En outre, en passant, si vous copiez par la valeur que vous "tranche" ainsi:

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

Reportez-vous à l'extrait de code ci-dessous:

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

où, parentObject est de type Parent*

Assurez-vous que "parentObject" est réellement de type "Child", sinon un comportement non défini.

Référez-vous à More Info

Questions connexes