Search code examples
c++virtualdeep-copydowncastupcasting

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


My objective is to do a deep copy of a class, but a virtual class is causing trouble.

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

The compilation error message:

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’

I plan to have plenty more Handler classes (like Handler1, Handler2 etc) which inherit from Vir and will have their own unique members (like float a; or double b; etc). So it doesn't make sense for me to keep all the getter & setter functions of all Handler classes in the Vir class. I want to keep my getter and setter methods in the Handler classes because the members are unique to the Handler classes. The compiler is not allowing me to do so. Help?


Solution

  • 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() )
    {
    }