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