2010-06-28 9 views
5

Voici ce que je suis en train de faire (ce code ne fonctionne pas):Comment une classe C++ dérivée peut-elle se cloner via un pointeur de base?

class Base 
{ 
    virtual Base *clone() { return new Base(this); } 
    virtual void ID() { printf("BASE"); 
}; 

class Derived : publc Base 
{ 
    virtual Base *clone() { return new Derived(this); } 
    virtual void ID() { printf("DERIVED"); } 
} 

. 
. 
Derived d; 
Base *bp = &d; 
Base *bp2 = bp->clone(); 

bp2->ID(); 

Ce que je comme est de voir « Dérivée » imprimé ... ce que je reçois est « BASE ". Je suis un programmeur C de longue date, et assez expérimenté avec le C++ ... mais je ne fais pas de progrès avec celui-ci ... toute aide serait appréciée.

+0

Afficher plus de code, en particulier tous les constructeurs de chaque classe dans ce cas est important. (Certains peuvent être déduits de votre code, mais cela aide à obtenir des réponses plus correctes de la part de tout le monde ...) – Macke

+0

Hm. Le code initial avait Base bp = & d. Maintenant, il a été changé en Base * bp = & d; – Macke

+0

Pas pertinent à la question, mais vous aurez également besoin de destructeurs virtuels sur les classes. –

Répondre

0

Vous êtes slicing la classe Base bp = &d; (ce construit une nouvelle base pb de la dérivée-PTR.)

Essayez Base* bp = &d; à la place. (Par exemple créer un pointeur de type base de l'objet dérivé.)

+1

Je ne vois pas une instruction d'édition sur l'OP (à ce moment), et le code est déjà en train de faire comme vous le suggérez (bien qu'il ne compile pas du tout). Bien que le problème signalé ne résout certainement pas un problème de tranchage, le code affiché ne le démontre pas ... Edit: Oups, je regardais le mauvais message pour la marque d'édition. Vous avez raison, Marcus. Désolé pour le dérangement. –

1

Avec Base bp = &d;

Vous avez « découpé en tranches » d, ainsi que le compilateur, bp est vraiment seulement de type Base, ce qui est pourquoi, lorsque vous appelez bp->clone() le compilateur appelle Base::clone(); et bp2->ID() imprime BASE.

Base& bp = d; fera ce que vous voulez.

0

Votre exemple est incorrect et ne sera pas compilé. Plus précisément cette ligne:

Base bp = &d; 

Cela peut aussi être la cause de votre problème (vous pouvez être tranchage votre objet), mais je ne peux pas dire avec certitude sans voir le code de travail.

Vous avez également un problème où vos deux classes ne sont pas liés (avez-vous l'intention d'écrire class Derived : public Base?)

+0

Oui, je sais que ce code ne sera pas compilé. J'ai corrigé ce bug dans une minute après l'avoir posté, mais vous êtes rapides! S'il vous plaît voir la question corrigée. Je ne sais pas ce que "tranchage" est, mais je le cherche ... – wanlessv

+1

@wanlessv - vous devez toujours vous assurer que votre code compile avant de poster une question. Sans savoir exactement ce que vous essayez de faire, nous ne pouvons pas toujours voir quel est le problème. –

3

Ce code est truffé d'erreurs syntaxiques. Peut-être le plus important, Derived n'hérite pas de Base. Deuxièmement, mis à part les erreurs syntaxiques (probablement de simples fautes de frappe), Base a évidemment besoin d'un destructeur virtuel. La méthode clone exige à peu près que vous puissiez appeler l'opérateur delete sur un pointeur de base (Base *).

class Base 
{ 
public: 
    virtual ~Base() {} 
    virtual Base* clone() const { return new Base(*this); } 
    virtual void ID() const { printf("BASE"); } 
}; 

class Derived: public Base 
{ 
public: 
    // [Edit] Changed return type to Derived* instead of Base*. 
    // Thanks to Matthieu for pointing this out. @see comments below. 
    virtual Derived* clone() const { return new Derived(*this); } 
    virtual void ID() const { printf("DERIVED"); } 
}; 

int main() 
{ 
    Derived d; 
    Base* bp = &d; 

    Base* bp2 = bp->clone(); 
    bp2->ID(); // outputs DERIVED as expected 
    delete bp2; 
} 
+1

J'admets à tous ... J'ai créé un exemple simple et l'ai posté, en essayant d'éviter d'enterrer tout le monde dans le code actuel ... mais j'ai fait plusieurs erreurs dans la version simple, et avant que je puisse revenir et les corriger, eu plusieurs réponses! À ce stade, je ne sais pas laquelle des réponses répond à mon exemple buggy, qui concerne toujours ma vraie question ... – wanlessv

+0

Il est également préférable d'utiliser un pointeur intelligent (tel que boost :: shared_ptr) pour supprimer automatiquement bp2. –

+0

@Daniel Oui, mais je me demande si l'OP a des difficultés avec l'héritage et le polymorphisme, il faudra peut-être un certain temps avant qu'il ne puisse comprendre RAII et les pointeurs intelligents. Les destructeurs virtuels – stinky472

7

Une fois que toutes les erreurs de compilation sont fixes, j'ai fini avec ceci:

#include <cstdio> 

class Base 
{ 
    public: 
    Base() {} 
    Base(const Base&) {} 
    virtual Base *clone() { return new Base(*this); } 
    virtual void ID() { printf("BASE"); } 
}; 

class Derived : public Base 
{ 
    public: 
    Derived() {} 
    Derived(const Derived&) {} 
    virtual Base *clone() { return new Derived(*this); } 
    virtual void ID() { printf("DERIVED"); } 
}; 


int main() 
{ 
    Derived d; 
    Base *bp = &d; 
    Base *bp2 = bp->clone(); 

    bp2->ID(); 
} 

Ce qui vous donne ce que vous cherchez - DÉRIVÉS.

+0

Merci à tous pour votre temps. En étudiant cet exemple, je pense que je comprends le problème. – wanlessv

0

Le code a l'air bien, autre que les fautes de syntaxe stupides et les ctors manquants.