c++ - 如何实现具有循环引用的对象的深拷贝或克隆?

标签 c++ oop clone

我有这样的层次结构:

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 指向位于不同立方体或同一个立方体中的球体。

这是正确撤消功能所必需的。

我还想要一张旧实体和克隆实体的 map :

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();
}

最佳答案

我将发布整个代码块作为答案:

#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;
}

关于c++ - 如何实现具有循环引用的对象的深拷贝或克隆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6214268/

相关文章:

c++ - 为什么对派生类使用基类指针

c++ - Qt安装不会复制文件

c++ - OpenSSL 内存 BIO 和部分密码 block

python - 为什么在 Python 中从类内部访问类变量需要 "self."?

Mysql用主键克隆行

linux - 将 git 命令与 -q 一起使用,但在失败时不会保持安静?

jquery - 如何使用 Jquery 复制表的第一行?

c++ - 不相交集 union 数据结构中的代表距离

c++ - 当 memcpy() 比 memmove() 快时,什么是真正重要的情况?

用于处理 AJAX 请求的 PHP OOP 模式