C++ 如何从undo/redo命令基类访问目标类的各种成员

C++ 如何从undo/redo命令基类访问目标类的各种成员,c++,qt,C++,Qt,我实现了一个undo/redo框架,并拥有一组支持更改角色类的各种属性的命令类。有多个10+派生类,每个派生类几乎完全相同,只是它所操作的角色类的特定属性不同 我想将这个cookiecuter代码推到基类中,并以某种方式让派生类提供成员操作的依据。这可能吗? 请注意,有些属性是布尔值,有些是双倍值 class character { public: double attribute1; double attribute2; double attribute3;

我实现了一个undo/redo框架,并拥有一组支持更改角色类的各种属性的命令类。有多个10+派生类,每个派生类几乎完全相同,只是它所操作的角色类的特定属性不同

我想将这个cookiecuter代码推到基类中,并以某种方式让派生类提供成员操作的依据。这可能吗? 请注意,有些属性是布尔值,有些是双倍值

class character
{
    public:


    double attribute1;
    double attribute2;
    double attribute3;
    double attribute4;
    //etc

    bool boolattribute1;
    bool boolattribute2;
    //etc

};


class CharacterCommand {    }
class CharacterCommandAttribute1 : public CharacterCommand { }
class CharacterCommandAttribute2 : public CharacterCommand { }
class CharacterCommandAttribute3 : public CharacterCommand { }
class CharacterCommandAttribute4 : public CharacterCommand { }


void CharacterCommandAttribute1::redo()
{
    std::vector<character*> chars = this->textbox->getSelectedCharacters(...);
    for(size_t c=0;c<chars.size();++c)
    {
        character * ch = chars[c];
        ch->attribute1 = this->doValue;
    }
}


void CharacterCommandAttribute1::undo()
{
    std::vector<character*> chars = this->textbox->getSelectedCharacters(...);
    for(size_t c=0;c<chars.size();++c)
    {
        if(c < this->undoValues.size())
        {
            character * ch = chars[c];
            ch->attribute1 = this->undoValues[c];
        }
    }
}

void CharacterCommandAttribute2::redo()
{
    std::vector<character*> chars = this->textbox->getSelectedCharacters(...);
    for(size_t c=0;c<chars.size();++c)
    {
        character * ch = chars[c];
        ch->attribute2 = this->doValue;
    }
}


void CharacterCommandAttribute2::undo()
{
    std::vector<character*> chars = this->textbox->getSelectedCharacters(...);
    for(size_t c=0;c<chars.size();++c)
    {
        if(c < this->undoValues.size())
        {
            character * ch = chars[c];
            ch->attribute2 = this->undoValues[c];
        }
    }
}
编辑 澄清一下:每个特定的命令类都派生自一个基类,并为纯虚拟撤销和重做功能提供重写。这些特定类存储在一个QUndoStack中,该QUndoStack根据需要调用命令的虚拟重做或撤消

每个特定命令负责为当前选择的一组“字符”设置单个用户界面属性的功能。特定命令将每个字符属性的现有状态存储在向量中,并使用这些状态提供撤消状态

一切正常;我只是觉得有太多的复制粘贴重复代码,唯一有意义的区别是

ch->attribute2=此->值;请参阅上面的::重做

ch->attribute2=this->undoValues[c];请参阅上面的::撤消


请记住,“attribute2”、“doValue”和“undoValues”向量类型在给定的派生类中是相同的,但在派生类集合中有所不同。这是阻止我将几乎所有内容移动到基类中的细节。

您应该能够在基类中实现撤销/重做方法,如果您将所有类都从基类中公开派生,那么您将能够修改基础数据,而不必派生一百个新类

例如,这将很好地工作:

class base {
  public:
    int x;
    void test() {x = 1;}
};

class derived : public base { };

int main() {
  derived temp;
  temp.test();
  return 0;
}
如果您希望一个函数能够影响所有字符属性,另一个函数能够影响所有布尔值,这应该可以:

class base {
  public:
    int x;
    char y;
    void change_char(char& attr) { attr = ';'; }
    void test() {x = 1;}

};

class derived : public base { };

int main() {
  derived temp;
  temp.change_char(temp.y);
  return 0;
}

希望这能有所帮助。

我提出的解决方案似乎效果很好。我将把它贴出来供其他人参考,并查看社区的反应。谢谢

我将CharacterCommand基类更改为模板类:

template<typename DO_TYPE, typename UNDO_TYPE>
class CharacterCommand : public TextBoxCommand
{
public:

...

//pure virtual functions that have to be overloaded in the base class
    virtual UNDO_TYPE getUndoValue(xite::Character * ch) = 0;
    virtual void performDo(xite::Character * ch, const DO_TYPE& doValue) = 0;
    virtual void performUndo(xite::Character * ch, const UNDO_TYPE& undoValue) = 0;

protected:
    int startSel;
    int endSel;

    std::vector<UNDO_TYPE> undoValues;
    DO_TYPE doValue;

};
一个示例派生类:

class CharacterHScale : public CharacterCommand<double,double>
{
public:
    ...

     double getUndoValue(xite::Character * ch);
    void performDo(xite::Character * ch, const double& doValue);
    void performUndo(xite::Character * ch, const double& undoValue);

...
};

这样,基类负责获取和操作目标字符的set std::vector,派生类负责通过每个派生类必须实现的虚拟performDo和performUndo函数设置/取消设置单个属性。

感谢您的响应。我已经编辑了我的问题来澄清。您的撤消功能是否必须不带任何参数?如果没有,则通过引用将变量传递到函数中,然后每次调用undo时,都传递相应的类变量。假设这是通过回调方法完成的,则不需要做那么多工作。是的,有一个存储指向实际基类QCommandUndo的指针的群堆栈。它提供了一个虚拟的undo和redo函数接口,通过该接口调用特定派生类的函数。