Как получить доступ к различным членам целевого класса из базового класса команд отменить / повторить - PullRequest
0 голосов
/ 09 апреля 2011

Я реализовал фреймворк отмены / повтора и получил набор командных классов, которые поддерживают изменение различных атрибутов класса символов.Существует несколько 10+ производных классов, каждый из которых практически одинаков, за исключением определенного атрибута класса символов, с которым он работает.

Я бы хотел вставить этот код резака печенья в базовый класс и каким-то образом получить производный класс, с которым он может работать.Возможно ли это?
Обратите внимание, что некоторые из атрибутов являются bools, а некоторые - двойными

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, который вызывает виртуальное повторение или отмену команды в зависимости от ситуации.

Каждая конкретная команда отвечает за функциональность настройки одного атрибута пользовательского интерфейса для набора «символов» (текущий выбор).Специальная команда сохраняет существующее состояние атрибута каждого символа в векторе и использует их для предоставления состояния отмены.

Все работает нормально;Я просто чувствую, что слишком много копирующих и вставляющих повторяющихся кодов, с единственной значительной разницей, это

ch-> attribute2 = this-> doValue;(см. выше: redo)

и

ch-> attribute2 = this-> undoValues ​​[c];(см. выше: отменить)

Имейте в виду, что векторные типы attribute2, doValue и undoValues ​​одинаковы в данном производном классе, но различаются в наборе производных классов.Это та деталь, которая мешает мне перенести почти все в базовый класс.

Ответы [ 2 ]

0 голосов
/ 13 апреля 2011

Решение, которое я нашел, похоже, работает очень хорошо. Я собираюсь опубликовать его для справки других и увидеть реакцию сообщества. Спасибо

Я изменил базовый класс 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);

...
};

Таким образом, базовый класс отвечает за получение и манипулирование набором (std :: vector) целевых символов, а производный класс отвечает за установку / удаление одного атрибута через виртуальные функции executeDo и executeUndo, которые каждый производный класс должен реализовать.

0 голосов
/ 09 апреля 2011

Вы должны быть в состоянии реализовать методы отмены / повторения внутри вашего базового класса, и если вы дадите всем своим классам открытую производную от базового класса, вы сможете изменять базовые данные без необходимости извлекать сто классы.

Например, это будет хорошо работать:

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

class derived : public base { };

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

Если вы хотите, чтобы одна функция могла воздействовать на все атрибуты char (и еще одну для всех bools), это должно работать:

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

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...