copia costruzione Cant essere fatto senza la creazione di una funzione esplicita nella classe base virtuale pura?

StackOverflow https://stackoverflow.com/questions/3813964

Domanda

Il mio obiettivo è quello di fare una copia profonda di una classe, ma una classe virtuale sta causando problemi.

#include<iostream>
using namespace std;

class Vir//pure virtual class
{
    public:
    virtual void hi()=0;
};

class Handler:public Vir
{
    public:
    int i;
    Handler() {}
    Handler(int val):i(val) {}
    void hi() {cout<<"Value of i="<<i<<endl;}
    int getI() const {return i;}
    void setI(int j) {i=j;}
};

class ControlPanel
{
    public:
    Vir *v;
    ControlPanel(const ControlPanel& c)//copy constructor
    {
        v=new Handler;
        v->setI(c.getI());
    }
    int getI()const {return v->getI();}

    void initialize() {v=new Handler(10);}
    void hi() {v->hi();}
    ControlPanel() {}
    ~ControlPanel() {delete v;}
};

int main()
{
    ControlPanel cc;
    cc.initialize();
    cc.hi();
    ControlPanel bb(cc);//copying cc into bb
}

Il messaggio di errore di compilazione:

test.cpp: In copy constructor ‘ControlPanel::ControlPanel(const ControlPanel&)’:
test.cpp:28: error: ‘class Vir’ has no member named ‘setI’
test.cpp: In member function ‘int ControlPanel::getI() const’:
test.cpp:30: error: ‘class Vir’ has no member named ‘getI’

Ho intenzione di avere molto di più classi Handler (come Handler1, Handler2 ecc) che ereditano da Vir e avrà i propri membri unici (come float a; o doppio b; ecc). Quindi non ha senso per me mantenere tutte le funzioni getter e setter, di tutte le classi Handler nella classe Vir. Voglio mantenere i miei metodi getter e setter nelle classi Handler perché i membri sono unici per le classi Handler. Il compilatore non mi permette di farlo. Aiuto?

È stato utile?

Soluzione

Forse mi manca qualcosa, ma non sareste meglio con un metodo clone virtuale su Vir? Questo significa che si può evitare la brutta getto nel costruttore ControlPanel copia delineato nella vostra risposta. Questo è lo stesso come suggerisce @Andrew Aylett in la sua risposta con duplicate in uso al posto di clone.

Qualcosa di simile

class Vir
{
    public:
    virtual Vir* clone() const = 0;
    ...
};

che viene realizzato in Handler di essere

Handler* Handler::clone() const
{
    return new Handler( *this );
}

Si noti l'utilizzo del tipo di ritorno covariante cioè Handler::clone è consentito di restituire un Handler* piuttosto che solo un Vir* e ancora una sostituzione valida di Vir::clone.

In questo modo il costruttore ControlPanel copia semplicemente

ControlPanel( const ControlPanel& c )
    : v( c.v->clone() )
{
}

Altri suggerimenti

Aggiungere una funzione duplicate() alla classe astratta, che (in ogni classe derivata) crea una nuova istanza con i valori giusti e lo restituisce. In alternativa, si consideri una funzione copyFrom(Abs other) che controlli per garantire che si sta copiando dal tipo corretto e se è così, copia i campi fuori.

In generale, se la classe ControlPanel ha un riferimento a un oggetto Abs, non dovrebbe essere cercando di fare la sua duplicazione ispezionando l'oggetto Handler concreto, dovrebbe essere superato la duplicazione fuori ad una funzione virtuale su tale oggetto.

Perché il compilatore permettere? Questi metodi non sono su tale interfaccia.

Si potrebbe utilizzare il fabbrica modello per creare la tua Vir, per evitare di dover aggiungere tutti i costruttori per l'interfaccia di Vir. Si dovrebbe anche considerare l'utilizzo di RAII per evitare di inizializzare le funzioni di stile ().

Cambia Vir *v a Handler *v; e vedere se i vostri compila codice o meno.

La classe Vir non dichiara / definire funzioni setI() e membro getI().

Oppure stabilire Vir come

class Vir//pure virtual class
{
    public:
    virtual void hi()=0;
    virtual int getI()const =0;
    virtual void setI(int)=0;
};

È necessario definire getI e setI come (puro) virtuale in Vir per renderli accessibili tramite sottoclassi. Nessun modo per aggirare questo.

Come Steve suggerito, sto rispondendo alla mia domanda coz un amico mi ha dato una soluzione. Spero che questo sarebbe di aiuto a chi ha il problema di come fare una copia profonda in C ++ dove una classe virtuale può essere un posto di blocco. La speranza qualcuno trova questo utile.

#include<iostream>
using namespace std;

class Vir//pure virtual class
{
    public:
    virtual void hi()=0;
    virtual int getI() {std::cout << "Inside Base class" << std::endl;}
    virtual void setI(int i) {cout<<"In base"<<endl;}
    virtual int getX() {}
    virtual void setX(int x) {}
};
class Model
{
    public:
    int x;
    Model(const Model& mm) {x=mm.x;}
    Model():x(555) {cout<<"Model constructor called"<<endl;}
    int getX() {return x;}
    void setX(int xx) {x=xx;}
};

class Handler:public Vir
{
    public:
    int i;
    Model *m;

    Handler() {m=new Model;cout<<"Handler constructor called"<<endl;}
    Handler(const Handler& h)
    {
    std::cout << "Inside Handler @lineNumber:" << __LINE__ << std::endl;
    i=h.i;
    m=new Model(*h.m);
    }
    Handler(int val):i(val) {}
    ~Handler() {delete m;}
    void hi() {cout<<"Value of i="<<i<<endl;}
    int getI() {return i;}
    void setI(int j) {i=j;}
    int getX() {return m->getX();}
    void setX(int xx) {m->setX(xx);}
};

class ControlPanel
{
    public:
    int abc;
    Vir *v;
    ControlPanel(const ControlPanel& c)//copy constructor
    {
    std::cout << "Inside ControlPanel @lineNumber:" << __LINE__ << std::endl;
        v=new Handler((Handler&)*(c.v));
    }
    void initialize() {v=new Handler();v->setI(10);abc=222;}
    void hi() {v->hi();}
    ControlPanel() {}
    ~ControlPanel() {delete v;}
};

int main()
{
    ControlPanel cc;
    cc.initialize();
    cc.hi();    
    cout << "(cc.v)->i::" << (cc.v)->getI() << endl;
    cout<<"x value cc="<<(cc.v)->getX()<<endl;
    ControlPanel bb(cc);//copying cc into bb
    cout << "(bb.v)->i::" << (bb.v)->getI() << endl;
    cout<<"x value bb="<<(bb.v)->getX()<<endl;
    (cc.v)->setI(999);
    (cc.v)->setX(888888888);
    cout << "(cc.v)->i::" << (cc.v)->getI() << endl;
    cout << "(bb.v)->i::" << (bb.v)->getI() << endl;
    cout<<"x value cc="<<(cc.v)->getX()<<endl;
    cout<<"x value bb="<<(bb.v)->getX()<<endl;
}//main
/*
Output:
Model constructor called
Handler constructor called
Value of i=10
(cc.v)->i::10
x value cc=555
Inside ControlPanel @lineNumber:52
Inside Handler @lineNumber:32
(bb.v)->i::10
x value bb=555
(cc.v)->i::999
(bb.v)->i::10
x value cc=888888888
x value bb=555  */
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top