我正尝试对类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
具有两个派生类Derived1
和Derived2
,这是否意味着我必须在每个目录中深度复制Base
的成员他们吗?
还有其他方法可以解决这个问题吗?
答案 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);
}
};