我想执行指向多态类的指针的STL容器的“深拷贝”。C++虚构造器,没有克隆()
我了解原型设计模式,由虚拟构造函数成语来实现,如C++ FAQ Lite, Item 20.8解释。
它是简单明了:
struct ABC // Abstract Base Class
{
virtual ~ABC() {}
virtual ABC * clone() = 0;
};
struct D1 : public ABC
{
virtual D1 * clone() { return new D1(*this); } // Covariant Return Type
};
深拷贝则是:
for(i = 0; i < oldVector.size(); ++i)
newVector.push_back(oldVector[i]->clone());
缺点
正如安德烈Alexandrescu的states it:
的
clone()
实现必须遵循在所有派生类中相同的模式SES;尽管它有重复的结构,但是没有合理的方法来自动定义clone()
成员函数(即超出宏)。
此外,ABC
的客户可能会做一些坏事。 (我的意思是,没有什么能阻止客户做坏事,所以,将会发生。)
更好的设计?
我的问题是:是否有另一种方法来使抽象基类可克隆而不需要派生类来编写与克隆相关的代码? (Helper class?Templates?)
以下是我的上下文。希望这将有助于理解我的问题。
我设计一个类层次结构上的一类Image
执行操作:
struct ImgOp
{
virtual ~ImgOp() {}
bool run(Image &) = 0;
};
图像操作是用户定义的:类层次的客户端将实现他们自己的类从ImgOp
得出:
struct CheckImageSize : public ImgOp
{
std::size_t w, h;
bool run(Image &i) { return w==i.width() && h==i.height(); }
};
struct CheckImageResolution { ... };
struct RotateImage { ... };
...
可以在图像上依次执行多个操作:
bool do_operations(vector< ImgOp* > v, Image &i)
{
for_each(v.begin(), v.end(),
/* bind2nd(mem_fun(&ImgOp::run), i ...) don't remember syntax */);
}
如果有多个图像,则该组可以拆分并在多个线程上共享。为了确保“线程安全性”,每个线程必须拥有包含在v
中的所有操作对象的- v
成为要在每个线程中深度复制的原型。
编辑:线程安全的版本使用原型设计模式来执行的指向的对象副本 - 不师生比:
struct ImgOp
{
virtual ~ImgOp() {}
bool run(Image &) = 0;
virtual ImgOp * clone() = 0; // virtual ctor
};
struct CheckImageSize : public ImgOp { /* no clone code */ };
struct CheckImageResolution : public ImgOp { /* no clone code */ };
struct RotateImage : public ImgOp { /* no clone code */ };
bool do_operations(vector< ImgOp* > v, Image &i)
{
// In another thread
vector< ImgOp* > v2;
transform(v.begin(), v.end(), // Copy pointed-to-
back_inserter(v2), mem_fun(&ImgOp::clone)); // objects
for_each(v.begin(), v.end(),
/* bind2nd(mem_fun(&ImgOp::run), i ...) don't remember syntax */);
}
这有感觉,当图像操作类是小:不要序列化对ImgOp
的唯一实例的访问,而是为每个线程提供自己的副本。
困难的部分是避免编写新的ImgOp
衍生类来编写任何与克隆相关的代码。 (因为这是实现细节 - 这就是为什么我用奇怪的循环模式解雇Paul的答案的原因。)
我认为实际上可以自动化clone()'(如果有点不雅):http://tydland.net/2009/06/covariant-templatized-virtual-copy-constructors/ – 2010-05-04 14:10:51
@tyler McHenry :但是使其自动化会鼓励使用不当,然后C++就会开始看起来像Java。我认为几乎所有的clone()用法都是错误的(在少数情况下,需要让人们去做实际的工作),不幸的是,这种方法很容易使用,从而导致错误的设计和实现。 – 2010-05-04 15:16:54
刚才定义和使用拷贝构造函数的方式有什么问题?正如@马丁所说,你绝对不希望对象被任意地克隆。 – jalf 2010-05-04 15:54:24