Não é possível copiar a construção sem criar uma função explícita na classe base virtual pura?
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?
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 Vir
interface. 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 */