📜  高级C++ |虚拟副本构造器

📅  最后修改于: 2021-05-30 12:34:54             🧑  作者: Mango

在虚拟构造函数中,我们看到了构造对象的方法,该对象的类型直到运行时才确定。是否可以在不知道其确切类类型的情况下创建对象?虚拟副本构造函数解决了这个问题。

有时我们可能需要从另一个现有对象构造一个对象。精确地,复制构造函数执行相同的操作。新对象的初始状态将基于另一个现有对象状态。从另一个对象实例化一个对象时,编译器将调用复制构造函数。但是,编译器需要具体的类型信息来调用适当的副本构造函数。

#include 
using namespace std;
  
class Base
{
public:
    //
};
  
class Derived : public Base
{
public:
    Derived()
    {
        cout << "Derived created" << endl;
    }
  
    Derived(const Derived &rhs)
    {
        cout << "Derived created by deep copy" << endl;
    }
  
    ~Derived()
    {
        cout << "Derived destroyed" << endl;
    }
};
  
int main()
{
    Derived s1;
  
    Derived s2 = s1;  // Compiler invokes "copy constructor"
                      // Type of s1 and s2 are concrete to compiler
  
    // How can we create Derived1 or Derived2 object
    // from pointer (reference) to Base class pointing Derived object?
  
    return 0;
}

如果我们不能决定要从哪种对象类型进行复制,该怎么办?例如,虚拟构造函数根据某些输入在运行时创建类层次结构的对象。当我们想从虚拟构造函数创建的另一个对象中复制构造一个对象时,我们不能使用通常的复制构造函数。我们需要一个特殊的克隆函数,该函数可以在运行时复制对象。

例如,考虑一个绘图应用程序。您可以选择一个已经在画布上绘制的对象,然后粘贴同一对象的另一个实例。从程序员的角度来看,我们无法确定哪个对象将被复制粘贴,因为它是运行时决策。我们需要虚拟副本构造函数来提供帮助。

同样,考虑剪贴板应用。剪贴板可以容纳不同类型的对象,并从现有对象复制对象,然后将其粘贴到应用程序画布上。同样,要复制的对象类型是运行时决策。虚拟副本构造函数填补了这里的空白。请参见下面的示例,

#include 
using namespace std;
  
//// LIBRARY SRART
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;
}

用户类借助虚拟构造函数创建对象。要创建的对象基于用户输入。 Action()正在复制正在创建的对象并修改其属性。借助Clone()虚拟函数创建的重复对象,该虚拟函数也被视为虚拟副本构造函数Clone()方法背后的概念是原型模式的基础

要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”