当派生类的基类具有成员指针时,深度复制

时间:2019-03-26 09:55:13

标签: c++ inheritance deep-copy

我正尝试对类d的对象Derived进行深层复制,如下代码所示:

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的new Derived(*this)方法中简单地返回clone()是错误的,因为它没有深度复制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的成员他们吗?

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

1 个答案:

答案 0 :(得分:0)

您可以考虑实现始终执行深层复制的复制构造函数。在这种情况下,您的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);
   }
};