跟踪巨大的对象树中的修改

时间:2011-03-02 08:36:49

标签: c++

我在C ++ / Qt中开发了一个图形编辑器,它使用对象树作为其数据模型。对象的类也构成了一个类层次结构。你可以在某种GUI框架中想到一个小部件树,比如Java Swing或Qt。现在我想实现一个撤消/重做功能。因此,我需要跟踪树节点的每个修改(例如,更改对象属性)以及树本身(例如,添加,删除节点)。不幸的是,树对象也将被第三方代码修改,我必须确保此代码不会破坏我的应用程序。

因此,考虑到树将是巨大的(几个100,000个节点),我如何确保,我可以看到对树的每次修改?还应该注意,树节点包含许多可修改的属性。

2 个答案:

答案 0 :(得分:3)

Command Pattern是一种方法。但是,对数据的每次修改都需要通过Command对象完成并由撤消系统记录。这是从一开始就最好的东西。改造可能会非常痛苦。

如果您无法通过第三方代码拦截修改并将其转换为命令,则可能只需在每次更改之前拍摄所有内容的快照。如果您的数据结构很大,则存在明显的问题。您可以在撤消堆栈上安装一个特殊命令,用于仅存储此类快照以进行第三方修改。

答案 1 :(得分:0)

我没有/ Qt的经验,但是虽然这在标准c ++中相当复杂,但是有可能。

在你从字面上理解我要说的内容之前,请注意我在发布之前没有在代码中尝试这个。这应该被理解为一般概念,而不是复制粘贴(可能存在错误)

首先,您需要一个基类来表示您的节点,我们称之为Node。节点应为任何值提供mutator。

class Node
{
public: // Methods
  template <typename Type>
  void Set(const char* name, GenericData& attribute) const
  {
    // Note that GenericData now is required to have an implemented copy constructor
    m_Attributes[name] = new Type(dynamic_cast<Type>(attribute));
    // Note the dynamic cast to prevent slicing

    // Call back some function to let it now the node changed here
  }

private: // Data
  // I just used a map for simplicity's sake. You should probably use
  // another container more adequate to your needs.
  std::map<std::string, GenericData*> m_Attributes;
}

然后我们需要一般地解决所有类型的不同类型,这也需要使用继承来完成。

class GenericData
{
public:
  virtual ~GenericData() {}
}

// Example Data
template <typename T>
class Data : public GenericData
{
public:
  ~Data(void) { delete m_Data; }
  T* get(void) const { return m_Data; }
  void set(T& dat)
  {
    delete m_Data;
    m_Data = new Data(); // Note: All data is now required to have default ctor
  }

private:
 T* m_Data;
}

然后客户端会输入如下内容:

Data<int> MyDat = 5; // Should be optimized to copy construction, therefore work
YourTree[TheNode].Set<int>("AttributeName", MyDat);

就像我说的,这是伪代码而不是实现,但它应该给出概念的概念。