【发布时间】:2014-07-30 15:51:21
【问题描述】:
我有一个非常复杂的课程。它在大型数组中有许多不同级别的数据。我在许多不同的上下文中使用这个对象。
问题:我们会在传递该对象时对其进行复制,但每个点对需要复制的内容和需要省略的内容都有不同的要求。结果,代码变得越来越难看,人们用 5-6 种不同的方式复制东西,从复制构造函数到克隆函数。它变得丑陋了。
我想做的事:我想以一种可外部扩展的方式解耦对象的构造。如果有人有一次性使用的特殊复制情况,我希望他们能够在相关的文件中创建一个函数或类,然后将其传递给克隆函数。
我想了一会儿,但想不出任何方法让外部函数/对象访问私有成员(不强制它)。这是我认为可行的一件事的示例:
class Dolly
{
public:
Dolly (int c = 0) : c(c) {}
struct Cloner
{
virtual Dolly* operator()(Dolly const& p) const
{ return new Dolly(p.c + 1); }
} cloneDeep;
Dolly* clone();
Dolly* clone(Cloner const& cloner)
{ return cloner(*this); }
protected:
int c;
};
class ShallowCloner : public Dolly::Cloner
{
Dolly* operator()(Dolly const& p) const
{ return new Dolly(p.c + 2); } // Error: cannot access c because its protected
} cloneShallow;
但是派生的ShallowCloner 无法访问其嵌套基类的父级受保护成员(哇,这句话。)
如果您知道任何可能有帮助的解决方案或设计模式,请告诉我。谢谢
编辑
睡了一夜好觉后,我决定使用标志来控制数据的复制。这与 Mark B 的答案并没有太大的不同,但由于标志的帮助,从长远来看并没有那么多代码。这是我正在考虑的当前框架(这是一个非常简化的示例):
class Dolly
{
public:
enum CopyData {
D1 = 0x01,
D2 = 0x02,
D3 = 0x04,
D4 = 0x08,
DEEP = D1 | D2 | D3 | D4
};
Dolly(int d1 = 0, int d2 = 0, int d3 = 0, int d4 = 0) :
d1(d1), d2(d2), d3(d3), d4(d4) {}
Dolly(Dolly const& cpy, int copyFlags = DEEP) {
copyDataFrom(cpy, copyFlags);
}
Dolly* clone(int copyFlags) {
return new Dolly(*this, copyFlags);
}
void copyDataFrom(Dolly const& cpy, int copyFlags) {
if (copyFlags & D1) {
copyD1From(cpy);
}
if (copyFlags & D2) {
copyD2From(cpy);
}
if (copyFlags & D3) {
copyD3From(cpy);
}
if (copyFlags & D4) {
copyD4From(cpy);
}
}
// Note that the real copies are more complex than this
inline void copyD1From(Dolly const& cpy) { d1 = cpy.d1; }
inline void copyD2From(Dolly const& cpy) { d2 = cpy.d2; }
inline void copyD3From(Dolly const& cpy) { d3 = cpy.d3; }
inline void copyD4From(Dolly const& cpy) { d4 = cpy.d4; }
protected:
int d1;
int d2;
int d3;
int d4;
};
int main()
{
Dolly dolly(1,2,3,4);
//Copy using constructor
Dolly dolly2(dolly, Dolly::D1 | Dolly::D2);
//Copy using clone
Dolly* dolly3 = dolly.clone(Dolly::D3 | Dolly::D4);
delete dolly3;
//Copy using copyFrom
Dolly dolly4;
// Maybe do stuff here...
dolly4.copyDataFrom(dolly, Dolly::D1 | Dolly::D3);
return 0;
}
这为类添加了很多代码,但它确实保持它的清洁和安全。所有的副本都保存在一个地方。受保护变量和私有变量保持私有。 API 保持相当简单(
【问题讨论】:
-
一个类应该负责它自己的复制。听起来类之间的交互不清楚。
-
如果我有几个月的时间,我会用数据库风格的解决方案替换对象,但此时,这对我来说并不是一个真正的选择。
-
你的例子太抽象了,我无法提出建议。如果您的克隆改变了对象的状态,那么它并不是真正的克隆。这更像是一种转变。一个类应该为其支持的所有转换提供函数。
-
这个例子只是为了展示一个很好的基本形式。我需要一个类似于数据库的对象。然后我在它上面调用一个复制类型的函数来获得一个较小的数据库,它是原始数据库的一个子集。目前,克隆和复制功能变得太多且令人困惑。最好在需要的地方定义复制。
-
“我有一个非常复杂的课程。”这就是你的麻烦开始的地方。该声明说您需要将您的类重构为一组更小、更简单的类。
标签: c++ design-patterns clone copy-constructor