我想对指向多态类的指针的 STL 容器执行“深拷贝” 。
我知道原型设计模式,它是通过Virtual Ctor Idiom实现的,如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() );
缺点
正如 Andrei Alexandrescu所说:
clone()
实现必须在所有派生类中遵循相同的模式;尽管其结构重复,但没有合理的方法来自动定义clone()
成员函数(即除了宏之外)。
此外,客户ABC
可能会做坏事。(我的意思是,没有什么能阻止客户做坏事,所以它会发生。)
更好的设计?
我的问题是:是否有另一种方法可以使抽象基类可克隆,而无需派生类编写与克隆相关的代码?(助手类?模板?)
以下是我的背景。希望这将有助于理解我的问题。
我正在设计一个类层次结构来对一个类执行操作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
成为要在每个线程中深度复制的原型。
编辑:线程安全版本使用原型设计模式来强制复制指向对象——而不是 ptrs:
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
s 的唯一实例的访问,而是为每个线程提供自己的副本。
困难的部分是避免新ImgOp
派生类的编写者编写任何与克隆相关的代码。(因为这是实现细节——这就是为什么我用奇怪的重复模式驳回了保罗的答案。)