Cant copy construction be done without creating an explicit function in the pure virtual base class?

落爺英雄遲暮 提交于 2019-12-06 09:22:31
Troubadour

Maybe I am missing something but would you not be better with a virtual clone method on Vir? This means you can avoid the nasty cast in the ControlPanel copy constructor outlined in your own answer. This is the same as @Andrew Aylett suggests in his answer with duplicate being used instead of clone.

Something like

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

which is implemented in Handler to be

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

Note the use of the covariant return type i.e. Handler::clone is allowed to return a Handler* rather than just a Vir* and still be a valid override of Vir::clone.

This makes the ControlPanel copy constructor simply

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

Add a duplicate() function to your abstract class, which (in each derived class) creates a new instance with the right values and returns it. Alternatively, consider a copyFrom(Abs other) function which checks to ensure that you're copying from the correct type and if so, copies the fields out.

In general, if your ControlPanel class has a reference to an Abs object, it shouldn't be trying to do its duplication by inspecting the concrete Handler object, it should be passing the duplication off to a virtual function on that object.

Why would the compiler allow you? Those methods are not on that interface.

You could use the Factory Pattern to create your Vir, to avoid having to add all of the constructors to Vir's interface. You should also consider using RAII to avoid initialize() style functions.

Change Vir *v to Handler *v; and see whether your code compiles or not.

Your class Vir doesn't declare/define setI() and getI() member functions.

Or define Vir as

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

You have to define getI and setI as (pure) virtual in Vir to make them accessible via subclasses. No way around this.

As Steve suggested, I'm answering my own question coz a friend gave me a solution. Hope this would be of help to anyone who has the question of how to do a Deep copy in C++ where a virtual class may be a roadblock. Hope someone finds this useful.

#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  */
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!