construcción copia no puede hacerse sin la creación de una función explícita en la clase base virtual pura?

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

Pregunta

Mi objetivo es hacer una copia profunda de una clase, pero una clase virtual está causando problemas.

#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
}

El mensaje de error de compilación:

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’

planeo tener mucha más clases Handler (como Handler1, Handler2 etc), que hereda de Vir y tendrá sus propios miembros únicos (como un flotador; b o doble; etc). Por lo tanto, no tiene sentido para mí mantener todas las funciones getter y setter de todas las clases de controlador en la clase Vir. Quiero mantener mis getter y setter métodos en las clases Handler porque los miembros son exclusivos de las clases Handler. El compilador no me permite hacerlo. Ayuda?

¿Fue útil?

Solución

Tal vez me estoy perdiendo algo, pero no estaría usted mejor con un método clone virtual en Vir? Esto significa que puede evitar el matiz desagradable en el constructor de copia ControlPanel esbozado en su propia respuesta. Este es el mismo que @ Andrew Aylett sugiere en su respuesta con duplicate que se utilizan en lugar de clone.

Algo así como

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

que se implementa en Handler sea

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

Tenga en cuenta el uso del tipo covariante retorno es decir Handler::clone se deja volver una Handler* en lugar de sólo un Vir* y todavía ser un override válida de Vir::clone.

Esto hace que el constructor de copia ControlPanel simplemente

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

Otros consejos

Añadir una función duplicate() a su clase abstracta, que (en cada clase derivada) crea una nueva instancia con los valores de la derecha y la devuelve. Como alternativa, considere una función copyFrom(Abs other) las que los controles para asegurarse de que está grabando de un tipo correcto y si es así, copia los campos cabo.

En general, si la clase Panel de Control tiene una referencia a un objeto Abs, no debería estar tratando de hacer su duplicación mediante la inspección del controlador de objeto concreto, debe ser pasar la duplicación fuera a una función virtual en ese objeto.

¿Por qué el compilador que permita? Estos métodos no son en esa interfaz.

Se podría utilizar el fábrica Patrón para crear su Vir, para evitar tener que añadir todos los constructores a la interfaz del Vir. También debe considerar el uso de RAII para evitar initialize funciones de estilo ().

Cambiar Vir *v a Handler *v; y ver si sus compila el código o no.

Su Vir clase no declarar / definir funciones setI() y miembros getI().

o definir como Vir

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

Tiene que definir getI y setI como (puro) virtual en Vir para que sean accesibles a través de las subclases. No hay forma de evitar esto.

Como Steve sugirió, estoy respondiendo a mi propia pregunta coz de un amigo me dio una solución. Espero que esto sería de ayuda para cualquier persona que tiene la cuestión de cómo hacer una copia profunda en C ++, donde una clase virtual puede ser un obstáculo. Esperanza que alguien encuentre esto útil.

#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  */
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top