Virtual Copy Constructor

Virtual Copy Constructor

It’s a way to construct an object whose type is not determined until run time

It’s different from copy constructor as object type is not known and  the compiler needs concrete type information to invoke appropriate copy constructor.

For example, virtual constructor creates an object of class hierarchy at runtime based on some input. When we want to copy construct an object from another object created by virtual constructor, we can’t use usual copy constructor. We need a special cloning function that can duplicate the object at runtime.

class Base
{
public:
    Base() { }
    virtual // Ensures to invoke actual object destructor
        ~Base() { }
    virtual void ChangeAttributes() = 0;
    // The "Virtual Constructor"
    static Base *Create(int id);
    // The "Virtual Copy Constructor"
    virtual Base *Clone() = 0;
};
class Derived1 : public Base
{
public:
    Derived1()
    {
        cout << "Derived1 created" << endl;
    }
    Derived1(const Derived1& rhs)
    {
        cout << "Derived1 created by deep copy" << endl;
    }
    ~Derived1()
    {
        cout << "~Derived1 destroyed" << endl;
    }
    void ChangeAttributes()
    {
        cout << "Derived1 Attributes Changed" << endl;
    }
    Base *Clone()
    {
        return new Derived1(*this);
    }
};
class Derived2 : public Base
{
public:
    Derived2()
    {
        cout << "Derived2 created" << endl;
    }
    Derived2(const Derived2& rhs)
    {
        cout << "Derived2 created by deep copy" << endl;
    }
    ~Derived2()
    {
        cout << "~Derived2 destroyed" << endl;
    }
    void ChangeAttributes()
    {
        cout << "Derived2 Attributes Changed" << endl;
    }
    Base *Clone()
    {
        return new Derived2(*this);
    }
};
class Derived3 : public Base
{
public:
    Derived3()
    {
        cout << "Derived3 created" << endl;
    }
    Derived3(const Derived3& rhs)
    {
        cout << "Derived3 created by deep copy" << endl;
    }
    ~Derived3()
    {
        cout << "~Derived3 destroyed" << endl;
    }
    void ChangeAttributes()
    {
        cout << "Derived3 Attributes Changed" << endl;
    }
    Base *Clone()
    {
        return new Derived3(*this);
    }
};
// We can also declare "Create" outside Base.
// But is more relevant to limit it's scope to Base
Base *Base::Create(int id)
{
    // Just expand the if-else ladder, if new Derived class is created
    // User need not be recompiled to create newly added class objects
    if( id == 1 )
    {
        return new Derived1;
    }
    else if( id == 2 )
    {
        return new Derived2;
    }
    else
    {
        return new Derived3;
    }
}
//// LIBRARY END
//// UTILITY SRART
class User
{
public:
    User() : pBase(0)
    {
        // Creates any object of Base heirarchey at runtime
        int input;
        cout << "Enter ID (1, 2 or 3): ";
        cin >> input;
        while( (input !=  1) && (input !=  2) && (input !=  3) )
        {
            cout << "Enter ID (1, 2 or 3 only): ";
            cin >> input;
        }
        // Create objects via the "Virtual Constructor"
        pBase = Base::Create(input);
    }
    ~User()
    {
        if( pBase )
        {
            delete pBase;
            pBase = 0;
        }
    }
    void Action()
    {
        // Duplicate current object
        Base *pNewBase = pBase->Clone();
        // Change its attributes
        pNewBase->ChangeAttributes();
        // Dispose the created object
        delete pNewBase;
    }
private:
    Base *pBase;
};
//// UTILITY END
//// Consumer of User (UTILITY) class
int main()
{
    User *user = new User();
    user->Action();
    delete user;
}
User class creating an object with the help of virtual constructor. The object to be created is based on user input. Action() is making duplicate of object being created and modifying it’s attributes. The duplicate object being created with the help of Clone() virtual function which is also considered as virtual copy constructor. The concept behind Clone() method is building block of prototype design pattern.
This can be treated as a valid prototype design pattern.

Leave a Reply

Your email address will not be published. Required fields are marked *