[英]copying c++ abstract classes
Ok heres some code.好的,这里有一些代码。
#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.
}
Now you might say, why don't you just put the pointers from the first deque into the second deque?现在你可能会说,为什么不把第一个双端队列的指针放到第二个双端队列中呢? While I could but I need the data to be independent.
虽然我可以,但我需要数据是独立的。 Basically I want to be able to clone items from the first deque while preserving there identity and giving them there own data.
基本上我希望能够从第一个双端队列中克隆项目,同时保留那里的身份并给他们自己的数据。
Now the current modified version现在是当前修改版本
#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.
}
The common pattern for handling that is through a virtual clone()
method in the base class that will create a new object of the appropriate type:处理的常见模式是通过基础 class 中的虚拟
clone()
方法,该方法将创建适当类型的新 object:
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
}
You need to provide a virtual copy constructor – usually this is a method called clone
– which is overridden in each class to return the correct type:您需要提供一个虚拟复制构造函数——通常这是一个称为
clone
的方法——它在每个 class 中被覆盖以返回正确的类型:
class A {
virtual A* clone() {
return new A();
}
};
class B : public A {
void A* clone() {
return new B();
}
};
The methods can of course be arbitrarily complex in order to copy the whole state.为了复制整个 state,这些方法当然可以任意复杂。
Of course, this leaks rather a lot of memory.当然,这泄露了相当多的 memory。 Use appropriate smart pointers instead of raw pointers (eg
std::shared_ptr
if your compiler supports it, boost::shared_ptr
otherwise).使用适当的智能指针而不是原始指针(例如,如果您的编译器支持
std::shared_ptr
,则使用boost::shared_ptr
否则)。
You have new A(...)
way down there.你在那里有
new A(...)
方式。 What gets called is A
's copy constructor (created implicitly by the compiler.调用的是
A
的复制构造函数(由编译器隐式创建。
What you want is a clone
method.你想要的是一个
clone
方法。 See here .见这里。 It recaps the appropriate item from the excellent C++ Coding Standards book.
它概括了优秀的C++ 编码标准书中的适当项目。 Below is a shameless copy of the final solution, which also shows a nice use of the NVI idiom to avoid the slicing problem.
下面是最终解决方案的无耻副本,它还展示了一个很好的使用NVI 成语来避免切片问题的方法。
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 ) {/* … */}
};
update A bit of an explanation.更新一点解释。 The basic idea of the clone is the same as the other excellent answers here.
克隆的基本思想与这里的其他优秀答案相同。
Now, with cloning you have the danger of slicing objects.现在,通过克隆,您有切割对象的危险。 For example, if some object which derives from
A
forgets to implement its own clone
method, then a call to A* a = d->clone()
will not return a full D
object (assuming D
is a descendant of A
)例如,如果从
A
派生的某些 object 忘记实现自己的clone
方法,则对A* a = d->clone()
的调用将不会返回完整的D
object (假设D
是A
的后代)
The NVI idiom says to separate a public interface from a virtual interface. NVI 习语说将公共接口与虚拟接口分开。 Thus, in this example,
clone
is public
, but not virtual
.因此,在此示例中,
clone
是public
,但不是virtual
。 It call a protected virtual
method, doClone
, which does the actual cloning, and which derived objects also implement.它调用一个
protected virtual
方法doClone
,该方法执行实际的克隆,并且派生对象也实现了该方法。 Because of the split, the clone
method can verify that the type of the cloned object matches the type of the original object.由于拆分,
clone
方法可以验证克隆的 object 的类型是否与原始 object 的类型匹配。
I think you confuse classes with objects , ie instances of those classes.我认为您将类与对象(即这些类的实例)混淆了。
Your container aclasses
store pointers to existing objects.您的容器
aclasses
存储指向现有对象的指针。 You may take the same pointer and push it several times in many different containers, this is not called cloning.您可以将同一个指针在许多不同的容器中多次推送,这不称为克隆。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.