我有这样的等级:
class Sphere;
class Cube;
class SpherePair;
class Entity {};
class Cube : public Entity {
public:
list<Sphere*> spheres_;
};
class Sphere : public Entity {
public:
Cube *cube;
SpherePair *spherepair;
};
class SpherePair : public Entity {
public:
Sphere *first;
Sphere *second;
};
我想要的是克隆Cube对象以及连接到它的所有对象(Sphere,SpherePair,Cube)。
Cube里面有Spheres,每个Sphere都是SpherePair对象的一半。 SpherePair指向位于单独的多维数据集或同一个多维数据集中的Spheres。
这是正确的撤消功能所必需的。
我还想要一张旧实体和克隆实体的地图:
std::map<Entity*, Entity*> old_new;
已添加:在这些循环引用之前,我有一个简单的克隆功能:
class Entity {
public:
virtual Entity* clone() = 0;
}
它被用于这样的方案:
std::vector<Entity*> selected_objects_;
void move(const vec3f &offset) {
document->beginUndo();
for(int i = 0; i < selected_objects_.size(); ++i) {
Entity *cloned = selected_objects_[i]->clone();
cloned->move(offset);
selected_objects_[i]->setDeleted(true);
document->pushToUndo(selected_objects_[i]);
document->addEntity(cloned);
}
document->endUndo();
}
答案 0 :(得分:3)
我将发布整个代码块作为答案:
#include <iostream>
#include <list>
#include <map>
#include <assert.h>
using std::cout;
using std::endl;
using std::list;
using std::make_pair;
using std::map;
using std::pair;
class Cube;
class Sphere;
class SpherePair;
class Entity {
public:
virtual ~Entity() {}
virtual Entity* clone() { return 0; }
virtual Entity* cloneDeep(map<Entity*, Entity*> *old_new) { return 0; }
protected:
bool cloneAndPush(Entity *e, map<Entity*, Entity*> *old_new) {
if (0 != old_new->count(e)) {
return false; // already cloned
}
typedef pair<map<Entity*, Entity*>::iterator, bool> insert_result;
Entity *cloned = e->clone();
insert_result inserted = old_new->insert(std::make_pair(e, cloned));
assert(inserted.second);
return inserted.second;
}
};
class Sphere : public Entity {
public:
Sphere() {
cout << "constructor Sphere" << endl;
}
virtual ~Sphere() {
cout << "destructor Sphere" << endl;
}
virtual Entity* clone();
virtual Entity* cloneDeep(map<Entity*, Entity*> *old_new);
Cube *cube;
SpherePair *spherepair;
};
class Cube : public Entity {
public:
Cube() {
cout << "constructor Cube" << endl;
}
virtual ~Cube() {
cout << "destructor Cube" << endl;
}
virtual Entity* clone() {
cout << "clone Cube" << endl;
Cube *c = new Cube(*this);
c->spheres_.clear();
return c;
}
virtual Entity* cloneDeep(map<Entity*, Entity*> *old_new) {
if (cloneAndPush(this, old_new)) {
Cube *c = static_cast<Cube*>((*old_new)[this]);
for(list<Sphere*>::iterator i = spheres_.begin(); i != spheres_.end(); ++i) {
c->addSphere(static_cast<Sphere*>((*i)->cloneDeep(old_new)));
}
}
return old_new->operator[](this);
}
void addSphere(Sphere *s) {
spheres_.push_back(s);
}
void delSphere(Sphere *s) {
spheres_.remove(s);
}
list<Sphere*> spheres_;
};
class SpherePair : public Entity {
public:
SpherePair() {
cout << "constructor SpherePair" << endl;
}
virtual ~SpherePair() {
cout << "destructor SpherePair" << endl;
delete first;
delete second;
}
virtual Entity* clone() {
cout << "clone SpherePair" << endl;
return new SpherePair(*this);
}
virtual Entity* cloneDeep(map<Entity*, Entity*> *old_new) {
if (cloneAndPush(this, old_new)) {
SpherePair *s = static_cast<SpherePair*>((*old_new)[this]);
s->first = (Sphere*)first->cloneDeep(old_new);
s->second = (Sphere*)second->cloneDeep(old_new);
}
return (*old_new)[this];
}
Sphere *first;
Sphere *second;
};
Entity* Sphere::clone() {
cout << "clone Sphere" << endl;
return new Sphere(*this);
}
Entity* Sphere::cloneDeep(map<Entity*, Entity*> *old_new) {
if (cloneAndPush(this, old_new)) {
Sphere *s = static_cast<Sphere*>((*old_new)[this]);
s->cube = (Cube*)cube->cloneDeep(old_new);
s->spherepair = (SpherePair*)spherepair->cloneDeep(old_new);
}
return (*old_new)[this];
}
inline void populateListSimpleCase(list<Entity*> *ents) {
Cube *first_cube = new Cube;
Cube *second_cube = new Cube;
// Cube *third_cube = new Cube;
ents->push_back(first_cube);
ents->push_back(second_cube);
for (int i = 0; i < 3; ++i) {
Sphere *first_cube_spheres = new Sphere;
Sphere *second_cube_spheres = new Sphere;
first_cube->addSphere(first_cube_spheres);
first_cube_spheres->cube = first_cube;
second_cube->addSphere(second_cube_spheres);
second_cube_spheres->cube = second_cube;
SpherePair *sp = new SpherePair;
sp->first = first_cube_spheres;
sp->second = second_cube_spheres;
ents->push_back(sp);
first_cube_spheres->spherepair = sp;
second_cube_spheres->spherepair = sp;
}
}
int main(int argc, char* argv[]) {
list<Entity*> ent_list;
populateListSimpleCase(&ent_list);
map<Entity*, Entity*> old_new;
(*ent_list.begin())->cloneDeep(&old_new);
for (list<Entity*>::iterator i = ent_list.begin(); i != ent_list.end(); ++i){
delete (*i);
}
ent_list.clear();
return 0;
}
答案 1 :(得分:0)
至于你的一般问题:将结构视为一个图形,内存中的对象作为顶点,指针作为边。以深度优先的方式走这个结构。通过浅层复制结构并逐个设置指针,将旧结构中节点地址的地图(最初为空)保存到新结构中的节点地址。每次遇到已经看过地址的子结构时(在地图中)停止递归。
...然而
这是正确的撤消功能所必需的。
我不确定我是否理解你的观点,但是你不需要循环引用来进行撤销。使用circular buffer代替(实际上只是一个带有一些标志和指针的平面数组)并使用结构共享(如果可能)来降低内存需求。
如果您的意思是需要深层复制以进行撤消,那么我仍然建议您考虑对象的某种“平面”图形表示。指针结构非常适合树和DAG,但在用于一般图形时非常混乱。
答案 2 :(得分:0)
您可以将此视为序列化和反序列化的特例。您将要复制的对象序列化为字节流,然后将其反序列化为新对象。这个C ++ FAQ提供了一些关于如何序列化越来越复杂的对象图的一些好的提示:http://www.parashift.com/c++-faq-lite/serialization.html \
当我需要做类似的事情时,我总是会回到这里。
答案 3 :(得分:0)
不确定这是否是您想要的,但是这里克隆图表(带或不带循环引用)
#include <iostream>
#include <map>
using namespace std;
struct Thing{
int length;
int id;
Thing *things[];
};
Thing* deepCopy(Thing *aThing,map<Thing*, Thing*> &aMap){
Thing *newThing = new Thing();
newThing->length = aThing->length;
newThing->id = aThing->id;
for(int i = 0 ;i < aThing->length;i++){
auto it1 = aMap.find(aThing->things[i]);
if(it1 == aMap.end()){
aMap.insert(pair<Thing*,Thing*>(aThing,newThing));
newThing->things[i] = deepCopy(aThing->things[i],aMap);
}else{
newThing->things[i] = it1->second;
}
}
return newThing;
}
int main(){
Thing *aThing1 = new Thing();
Thing *aThing2 = new Thing();
Thing *aThing3 = new Thing();
//////INITIALIZE GRAPH ///////// You can ignore this block
aThing1->length = 2;
aThing1->id = 1;
aThing2->length = 2;
aThing2->id = 2;
aThing3->length = 1;
aThing3->id = 3;
aThing1->things[0] = aThing2;
aThing1->things[1] = aThing3;
aThing2->things[0] = aThing1;
aThing2->things[1] = aThing3;
aThing3->things[0] = aThing2;
//////END INITIALIZE GRAPH ///////// You can ignore this block
map<Thing*,Thing*> aMap;
Thing *myNewThing = deepCopy(aThing1,aMap);
return 0;
}
我在接受采访时得到了这个,我努力做到了。我非常接近解决方案,但我使用的是集合而不是地图,因此检索有点困难。
唯一重要的部分是deepCopy方法。其余的只是样板代码。