我正在尝试制作类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
的成员?
任何其他方法来解决这个问题?
您可以考虑实现始终执行深层复制的复制构造函数。在这种情况下,你的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);
}
};