Não é possível copiar a construção sem criar uma função explícita na classe base virtual pura?

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

Pergunta

Meu objetivo é fazer uma cópia profunda de uma classe, mas uma classe 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
}

A mensagem de erro de compilação:

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’

Eu pretendo ter muito mais aulas de manipulador (como Handler1, Handler2 etc) que herdam da VIR e terão seus próprios membros (como o Float A; ou B; B; etc). Portanto, não faz sentido manter todas as funções Getter & Setter de todas as classes de manipulador da classe Vir. Quero manter meus métodos Getter e Setter nas classes do manipulador porque os membros são exclusivos das classes de manipulador. O compilador não está me permitindo fazê -lo. Ajuda?

Foi útil?

Solução

Talvez eu esteja perdendo alguma coisa, mas você não seria melhor com um virtual clone método em Vir? Isso significa que você pode evitar o elenco desagradável no ControlPanel Copiar construtor descrito em sua própria resposta. É o mesmo que @andrew Aylett sugere em sua resposta com duplicate sendo usado em vez de clone.

Algo como

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

que é implementado em Handler ser

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

Observe o uso do tipo de retorno covariante, ie Handler::clone tem permissão para devolver um Handler* em vez de apenas um Vir* e ainda ser uma substituição válida de Vir::clone.

Isso faz o ControlPanel Copie o construtor simplesmente

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

Outras dicas

Adicione a duplicate() A função da sua classe abstrata, que (em cada classe derivada) cria uma nova instância com os valores certos e a retorna. Alternativamente, considere um copyFrom(Abs other) Função que verifica para garantir que você esteja copiando do tipo correto e, se assim for, copia os campos.

Em geral, se sua classe ControlPanel tiver uma referência a um objeto ABS, ele não deve estar tentando fazer sua duplicação inspecionando o objeto de manipulador de concreto, ele deve estar passando a duplicação para uma função virtual nesse objeto.

Por que o compilador permitiria você? Esses métodos não estão nessa interface.

Você poderia usar o Padrão de fábrica Para criar o seu Vir, para evitar ter que adicionar todos os construtores a Virinterface. Você também deve considerar usar Raii Para evitar inicializar () funções de estilo.

Mudar Vir *v para Handler *v; E veja se o seu código compila ou não.

Sua classe Vir não declara/define setI() e getI() Funções de membros.

Ou definir Vir Como

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

Você tem que definir getI e setI como (puro) virtual em Vir para torná -los acessíveis por subclasses. Não há como contornar isso.

Como Steve sugeriu, estou respondendo à minha própria pergunta porque um amigo me deu uma solução. Espero que isso ajude para quem tem a questão de como fazer uma cópia profunda no C ++, onde uma classe virtual pode ser um obstáculo. Espero que alguém ache isso ú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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top