2010-06-28 16 views
5

Ecco quello che sto cercando di fare (questo codice non funziona):In che modo una classe C++ derivata può clonare se stessa tramite un puntatore di 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(); 

quello che avevo come è quello di vedere "derivata" stampato ... quello che ottengo è "BASE ". Sono un programmatore C di lunga data e abbastanza esperto di C++ ... ma non sto facendo progressi con questo ... ogni aiuto sarebbe apprezzato.

+0

Mostrando più codice, in particolare tutti i costruttori di ogni classe in questo caso sono importanti. (Alcuni possono essere dedotti dal tuo codice, ma aiuta a ottenere risposte più corrette da tutti ...) – Macke

+0

Hm. Il codice iniziale aveva Base bp = & d. Ora è stato cambiato in Base * bp = & d; – Macke

+0

Non pertinente alla domanda, ma vorrete anche distruttori virtuali sulle classi. –

risposta

0

Sei slicing della classe in Base bp = &d; (questo costruisce un nuovo bp base dal PTR-derivato.)

Prova Base* bp = &d; invece. (Vale a dire creare un puntatore di tipo Base per l'oggetto derivato.)

+1

Non vedo un'istruzione di modifica sull'OP (al momento), e il codice sta già facendo come suggerisci (anche se non si compila affatto). Mentre il problema segnalato fa certamente male a un problema di affettamento, il codice postato non lo dimostra ... Modifica: Oops, stavo guardando il post sbagliato per il segno di modifica. Hai ragione, Marcus. Scusa per il disturbo. –

1

Con Base bp = &d;

Hai "affettato" d, in modo da al compilatore, bp è in realtà solo di tipo Base, motivo per cui quando si chiama il bp->clone() il compilatore chiama Base::clone(); e bp2->ID() stampe BASE.

Base& bp = d; farà quello che vuoi.

0

Il vostro esempio non è corretto e non verrà compilato. In particolare questa linea:

Base bp = &d; 

che può anche essere la causa principale del problema (si può essere affettando l'oggetto), ma non posso dirlo con certezza senza vedere il codice di lavoro.

Hai anche un problema in cui i tuoi due classi non sono correlati (Cercavi scrivere class Derived : public Base?)

+0

Sì, so che questo codice non verrà compilato. Ho corretto questo bug entro un minuto dal postarlo, ma voi ragazzi siete veloci! Si prega di vedere la domanda corretta. Non so cosa sia "slicing", ma lo sto cercando ... – wanlessv

+1

@wanlessv - devi sempre assicurarti che il codice venga compilato prima di pubblicare una domanda. Senza sapere esattamente cosa stai cercando di fare, non possiamo sempre vedere quale sia il problema. –

3

Quel codice è pieno di errori di sintassi. Forse la cosa più significativa, Derived non eredita da Base. In secondo luogo, a parte gli errori sintattici (probabilmente semplici errori di battitura), Base ha ovviamente bisogno di un distruttore virtuale. Il metodo clone richiede praticamente di poter chiamare l'operatore delete su un puntatore di 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

Mi congratulo con tutti ... Ho creato un semplice esempio e l'ho postato, cercando di evitare di seppellire tutti nel codice reale ... ma ho commesso diversi errori nella versione semplice, e prima che potessi tornare indietro e correggerli, ho avuto diverse risposte! A questo punto, non so quali risposte stanno rispondendo al mio buggy esempio, che riguarda ancora la mia vera domanda ... – wanlessv

+0

È anche meglio usare un puntatore intelligente (come boost :: shared_ptr) per elimina automaticamente bp2. –

+0

@Daniel Sì, ma immagino che se l'OP ha difficoltà con l'ereditarietà e il polimorfismo, potrebbe essere un po 'di tempo prima che possa capire RAII e puntatori intelligenti. I distruttori virtuali – stinky472

7

Una volta che tutti gli errori di compilazione sono fissi, ho finito con questo:

#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(); 
} 

che ti dà quello che state cercando - DERIVATI.

+0

Grazie a tutti per il vostro tempo. Studiando questo esempio, penso di aver capito il problema. – wanlessv

0

Il codice sembra buono, a parte gli errori di sintassi stupidi e i sensori mancanti.

Problemi correlati