2009-08-10 5 views
1

J'étais un peu surpris que le code suivant ne fonctionne pas comme prévu:Les fonctions virtuelles peuvent-elles être utilisées dans les valeurs de retour?

#include "stdio.h" 

class RetA 
{ 
public: 
    virtual void PrintMe() { printf ("Return class A\n"); } 
}; 

class A 
{ 
public: 
    virtual RetA GetValue() { return RetA(); } 
}; 

class RetB : public RetA 
{ 
public: 
    virtual void PrintMe() { printf ("Return class B\n"); } 
}; 

class B : public A 
{ 
public: 
    virtual RetA GetValue() { return RetB(); } 
}; 

int main (int argc, char *argv[]) 
{ 
    A instance_A; 
    B instance_B; 
    RetA ret; 

    printf ("Test instance A: "); 
    ret = instance_A.GetValue(); 
    ret.PrintMe(); // Expected result: "Return class A" 

    printf ("Test instance B: "); 
    ret = instance_B.GetValue(); 
    ret.PrintMe(); // Expected result: "Return class B" 

    return 0; 
} 

Ainsi, les méthodes virtuelles ne fonctionne pas lors du retour d'une valeur? Devrais-je revenir à l'allocation de la classe de retour sur le tas, ou y a-t-il un meilleur moyen?

(En réalité, je veux le faire pour laisser quelques classes différentes héritant d'une classe de conteneur pour revenir différentes instances de classe itérateur selon la classe ...)

+0

Je ne sais pas, comme je suis nouveau à C/C++, mais sommes-nous autorisés à avoir des classes en C, il semble que vous travaillez en C que vous avez stdio.h et printf; Si vous utilisez C++, ce n'est pas une bonne idée de mélanger C-ish printf et C++ - ish-cout AFAIK, mais je ne suis pas tout à fait sûr cependant. J'aimerais en savoir plus à ce sujet auprès des autres. –

+1

si vous savez ce que vous faites, ce n'est pas un problème de "mélanger" C et C++ –

Répondre

17

Le comportement polymorphe ne fonctionne pas par valeur, vous devez renvoyer des pointeurs ou des références pour que cela fonctionne. Si vous retournez par valeur, vous obtenez ce que l'on appelle le "découpage", ce qui signifie que seule la partie parente de l'objet est retournée, donc vous avez rayé avec succès un objet enfant dans un objet parent, ce qui n'est pas sûr. tout.

Jetez un oeil à: What is object slicing?

0

Do obtenir une surcharge dynamique, vous devez avoir la type statique différent du type dynamique. Vous n'êtes pas ici. Renvoie une référence ou un pointeur (et fait attention à la durée de vie) au lieu d'une valeur.

0

virtuel est applicable à pointeur ou déclaration de référence de type, donc changer votre code: Reta virtuel & GetValue() ou GetValue() virtuel Reta *, Mais vous émettez pas virtuel - que vous utilisez « copie sémantique ».

0

vous devez retourner un pointeur ou adresse

virtual RetA GetValue() { return RetB(); } 

sinon, ce que vous obtenez de GetValue est un Reta pas RETB.

0

Outre le problème de «découpage» déjà mentionné, la méthode PrintMe doit également être virtuelle.

struct B 
{ 
    void print1() const { std::cout << "B" << std::endl; } 
    virtual void print2() const { print1(); } 
}; 
struct D : public B 
{ 
    void print1() const { std::cout << "D" << std::endl; } 
    virtual void print2() const { print1(); } 
}; 
B& f() 
{ 
    static D d; 
    return d; // the object returned is in fact a D, not a B 
} 
int main(){ 
    f().print1(); // B: calling a non-virtual method from a B reference 
    f().print2(); // D: the method is virtual will exec B::print2 
} 
+0

Oups, bien sûr. C'était en fait dans mon test, juste une faute de frappe dans mon post. – Jonatan

Questions connexes