复制抽象基类对象

5

如果我有一个指向从抽象基类派生的对象的指针(因此我无法创建该类的新对象),并且我希望制作所述对象的深层副本,是否有比使抽象基类创建每个继承类都必须实现新的纯虚拟copy 函数更简明的方法?


什么让你觉得它效率低下? - GManNickG
@GMan "inefficient" 一词是指相对于某些聪明的一行代码或其他能够完成同样任务的技巧而言,需要程序员投入更多的工作量(就像我有时在Stackoverflow上发现的情况一样)。 - wrongusername
你想要的词是“简洁”。你可能需要在问题中详细说明这一点,并明确你所指的是可维护性和清晰度,而不是性能。 - GManNickG
@GMan 谢谢,我已经纠正了问题! - wrongusername
3个回答

10

不,但是copy方法并不一定很痛苦:

class Derived : public Base
{
  public:
    Base *copy() const
    {
        return new Derived(*this);
    }
};

(假设您已经有了一个拷贝构造函数,如果需要深拷贝,您就会有这个函数)。


1
你应该在基类中将copy方法定义为纯虚函数,这样编译器会在你忘记提供它时告诉你。 - Mark Ransom
1
@Mark - 这只会提供一种虚假的安全感,因为任何孙子辈也可能会忘记。 - Edward Strange
@Noah,太真实了。但这只是避免有孙子辈的一个原因,我还可以提供其他原因。 - Mark Ransom

1
建议使用“克隆”而不是“复制”,这是常规方法。另一种方法是使用RTTI创建工厂和调度程序,以查找正确的处理程序,然后调用派生类型的复制构造函数。
struct Abc
{
    virtual void who() const = 0;
};

struct A : Abc
{
    virtual void who() const { std::cout << "A" << std::endl;}
};

template<class T>
Abc* clone(Abc* abc)
{
    T* t = dynamic_cast<T*>(abc);
    if (t == 0)
        return 0;
    return new T(*t);
}

struct B : Abc
{
    virtual void who() const { std::cout << "B" << std::endl;}
};

typedef Abc* (*Cloner)(Abc*);

std::map<std::string, Cloner> clones;

void defineClones()
{
    clones[ typeid (A).name() ] = &clone<A>;
    clones[ typeid (B).name() ] = &clone<B>;
}


Abc* clone(Abc* abc)
{
    Abc* ret = 0;
    const char* typeName  = typeid(*abc).name();
    if (clones.find(typeName) != clones.end())
    {
        Cloner cloner = clones[typeName];
        ret = (*cloner)(abc);
    }
    return ret;
}
void test ()
{
    defineClones();
    Abc* a = new A;
    Abc* anotherA = clone(a);
    anotherA->who();

    Abc* b = new B;
    Abc* anotherB = clone(b);
    anotherB->who();
}

虽然上述方法可行,但它使用了RTTI,这足以说服大多数人采用正常的方法。然而,如果有什么原因阻止对基类进行更改,那么这种方法可能会很有用。

这个方法有效吗?添加新类型的边际成本确实只有一行代码。问题在于,很容易忘记在每个新类中添加该行代码。或者你可以把它看作是一个优点,所有克隆代码都存在于单个文件中,我们不必更改支持的层次结构来处理它。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接