复制c ++抽象类

时间:2011-06-01 20:04:16

标签: c++ arrays inheritance

好的,还有一些代码。

#include <iostream>
#include <deque>
using namespace std;
class A
{
public:
    virtual void Execute()
    {
        cout << "Hello from class A" << endl;
    }
};
class B: public A
{
public:
    void Execute()
    {
        cout << "Hello from class B" << endl;
    }
};
void Main()
{
    deque<A *> aclasses = deque<A*>(0);
    deque<A *> aclasses2 = deque<A*>(0);
    A a1 = A();
    B b1 = B();
    aclasses.push_back(&a1);
    aclasses.push_back(&b1);
    aclasses[0]->Execute();
    aclasses[1]->Execute();

    //Now say I want to copy a class from aclasses to aclasses2
    //while perserving it's identity and making it a seperate entity, without
    //knowing the exact type it is.

    aclasses2.push_back(new A(*aclasses[0]));
    aclasses2.push_back(new A(*aclasses[1]));
    //Now my problem show itself
    for each(A * a in aclasses2)
        a->Execute();
    //Execute is called from the original class A both times.

}

现在你可能会说,为什么不把第一个双端的指针放到第二个双端?虽然我可以,但我需要数据是独立的。基本上我希望能够从第一个双端队列中克隆项目,同时保留其身份并为其提供自己的数据。

现在是当前修改后的版本

#include <iostream>
#include <deque>
using namespace std;
class A
{
public:
    virtual void Execute()
    {
        cout << "Hello from class A" << endl;
    }
    virtual ~A() {}             // don't forget the virtual destructor
    virtual A* clone() const {
       return new A(*this);
    }
};
class B: public A
{
public:
    void Execute()
    {
        cout << "Hello from class B" << endl;
    }
    virtual B* clone() {     // return type is co-variant
       return new B( *this );
    }
};
void MainRUNNER()
{
    deque<A *> aclasses = deque<A*>(0);
    deque<A *> aclasses2 = deque<A*>(0);
    A a1 = A();
    B b1 = B();
    aclasses.push_back(&a1);
    aclasses.push_back(&b1);
    aclasses[0]->Execute();
    aclasses[1]->Execute();

    //Now say I want to copy a class from aclasses to aclasses2
    //while perserving it's identity and making it a seperate entity, without
    //knowing the exact type it is.

    aclasses2.push_back(aclasses[0]->clone());
    aclasses2.push_back(aclasses[1]->clone());
    //Now my problem show itself
    for each(A * a in aclasses2)
        a->Execute();
    //Execute is called from the original class A both times.
}

4 个答案:

答案 0 :(得分:10)

处理的常见模式是通过基类中的虚拟clone()方法创建适当类型的新对象:

struct base {
    virtual ~base() {}             // don't forget the virtual destructor
    virtual base* clone() const { 
       return new base(*this); 
    }
};
struct derived : base {
    virtual derived* clone() const {     // return type is co-variant
       return new derived( *this );
    }
};
int main() {
   std::auto_ptr<base> b1( new derived );
   std::auto_ptr<base> b2( b1->clone() ); // will create a derived object
}

答案 1 :(得分:3)

您需要提供虚拟副本构造函数 - 通常这是一个名为 clone 的方法 - 在每个类中重写以返回正确的类型:

class A {
    virtual A* clone() {
        return new A();
    }
};

class B : public A {
    void A* clone() {
        return new B();
    }
};

这些方法当然可以是任意复杂的,以便复制整个州。

当然,这会泄漏相当多的内存。使用适当的智能指针而不是原始指针(例如std::shared_ptr如果编译器支持它,否则为boost::shared_ptr

答案 2 :(得分:1)

你有new A(...)路。被称为A的复制构造函数(由编译器隐式创建。

您想要的是clone方法。见here。它从优秀的C++ Coding Standards书中回顾了相应的项目。下面是最终解决方案的无耻副本,它还显示了NVI idiom的良好用法,以避免slicing问题。

class A {// …
public:
  A* Clone() const {                        // nonvirtual
    A* p = DoClone();
    assert( typeid(*p) == typeid(*this) && "DoClone incorrectly overridden" );
    return p;                                // check DoClone's returned type
  }

protected:
 A( const A& );
 virtual A* DoClone() const = 0;
};

class B : public A { // …
public:
  virtual B* Clone() const {return new B(*this); }

protected:
  B( const B& rhs ) : A( rhs ) {/* … */}
};

<强>更新 一点解释。克隆的基本思想与此处的其他优秀答案相同。

现在,通过克隆,您将面临切片对象的危险。例如,如果某个派生自A的对象忘记实现自己的clone方法,则对A* a = d->clone()的调用将不会返回完整的D对象(假设{{ 1}}是D

的后代

NVI习惯用于将公共接口与虚拟接口分开。因此,在此示例中,Aclone,但不是public。它调用virtual方法protected virtual,它执行实际克隆,以及哪些派生对象也实现。由于拆分,doClone方法可以验证克隆对象的类型是否与原始对象的类型匹配。

答案 3 :(得分:-1)

我认为您将对象混淆,即这些类的实例。

您的容器aclasses指针存储到现有对象。您可以使用相同的指针并在许多不同的容器中将其推送几次,这是称为克隆。