当派生类的基类具有成员指针时,对其进行深层复制

Deep-copying a derived class when its base class has member pointers

本文关键字:复制 指针 派生 基类 成员      更新时间:2023-10-16

我正在尝试制作类Derived的对象d的深层副本,如下代码所示:

class A {
public:
   int m_int;
   A* clone() {
      return new A(*this);
   }
};
class Base {
public:
   A* m_a;
   virtual Base* clone() {
      A* new_a = new A();
      new_a = this->m_a->clone();
      Base* clone = new Base(*this);
      clone->m_a = new_a;
      return clone;
   }
};
class Derived : public Base {
public:
   double m_dbl;
   virtual Derived* clone() {
      return new Derived(*this);
   }
};
int main() {
   Derived* d = new Derived();
   d->m_dbl = 1.234;
   A* a = new A();
   a->m_int = -1;
   d->m_a = a;
   //clone d
   Derived d_copy = d->clone();
   //changing values of d's attributes must not affect d_copy
   a->m_int = 10;
   d->m_dbl = 3.456;
   //check d_copy
   cout << "m_int " << d_copy->m_a->m_int << endl;
   cout << "m_dbl " << d_copy->m_dbl << endl;
}

输出:

m_int 10 //wrong, should be -1;
m_dbl 1.234 //correct

如您所见,简单地在 Derived 的 clone() 方法中返回new Derived(*this)是错误的,因为它不会m_a进行深度复制。

如果我将m_a的深度复制从Base"降低"到Derived那么我会得到正确的答案:

   virtual Base* clone() = 0;
   ...
   virtual Derived* clone() {
      A* new_a = new A();
      new_a = this->m_a->clone();
      Derived* clone = new Derived(*this);
      clone->m_a = new_a;    
      return new Derived(*this);
   }
   //gives out m_int = -1

如果是这种情况,这是否意味着每次我从Derived创建进一步的派生类时,我总是必须"降低"clone()的内容?

另外,例如,如果Base有两个派生类Derived1Derived2,这是否意味着我必须在每个派生类中深度复制Base的成员?

还有其他方法可以解决这个问题吗?

您可以考虑实现始终执行深度复制的复制构造函数。在这种情况下,您的clone实现将永远是微不足道的:

class Base {
public:
   A* m_a;
   Base(const A& other)
       : m_a(other.m_a->clone())
   {       
   }
   virtual Base* clone() {
      return new A(*this);
   }
};
class Derived : public Base {
public:
   double m_dbl;
   Derived(const Derived& other)
       : m_dbl(other.m_dbl)
   virtual Derived* clone() {
      return new Derived(*this);
   }
};

如果不想更改默认构造函数的行为(例如,希望默认构造函数进行浅拷贝(,则替代方法是将复制实现移动到CopyTo方法,以便可以重用它:

class Base {
public:
   A* m_a;
   static void CopyTo(const Base& from, Base& to)
   {
        to.m_a = from.m_a->clone();
   }
   virtual Base* clone() {
      Base* result = new Base();
      CopyTo(*this, result);
      return result;
   }
};
class Derived : public Base {
public:
   double m_dbl;
   static void CopyTo(const Base& from, Base& to)
   {
        Base::CopyTo(from, to);
        to.m_dbl= from.m_dbl;
   }
   virtual Derived * clone() {
      Derived * result = new Derived ();
      CopyTo(*this, result);
      return result;
   }
   virtual Derived* clone() {
      return new Derived(*this);
   }
};