Объект ModelResetter RAII

У меня есть настраиваемая прокси-модель, которая время от времени перестраивается, когда в исходную модель добавляется новый столбец/строка. Из документов видно, что вызов QAbstractItemModel::beginResetModel() и QAbstractItemModel::endResetModel() в начале и конце такая операция является правильной методологией. Моя функция капитального ремонта, к сожалению, имеет несколько возможных точек выхода, и я просто знаю, что буду забывать вызывать endResetModel в каждой точке выхода, поскольку она становится более сложной.

Поэтому я хотел бы создать простой класс RAII, который будет вызывать beginResetModel при построении, а затем вызывать endResetModel при разрушении, как показано ниже:

class ModelResetter
{
public:
    ModelResetter(QAbstractItemModel* model) : m_model(model)
    {
        m_model->beginResetModel();
    }
    ~ModelResetter()
    {
        m_model->endResetModel();
    }

private:
    QAbstractItemModel* m_model;
};

Проблема в том, что beginResetModel() и endResetModel() оба являются protected в QAbstractItemModel. Объявление ModelResetter как friend class в моей унаследованной модели не помогает, так как я пытаюсь взаимодействовать с базовым классом.

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

Правка 1: (во избежание путаницы я удалил пример кода шаблона в редакции 2)

Было бы неплохо, если бы я мог каким-то образом ограничить шаблон, чтобы разрешить только типы, которые наследуют QAbstractItemModel, но я не вижу ничего в стандартном C++, что позволяет это. Я не буду использовать Boost.

Редактировать 2. Думаю, я не очень четко выразил свои требования. Они здесь:

  • Работает с базовым классом для общего случая
  • Применяет требование наследования QAbstractItemModel в режиме отладки без штрафных санкций в режиме выпуска.
  • Простое использование практически без накладных расходов
  • Не требует модификации базового класса или новых функций

person Phlucious    schedule 07.03.2013    source источник
comment
В основном это ситуация, противоположная этой ссылке. Обратите внимание, что beginResetModel() и endResetModel() не являются virtual в базовой реализации, поэтому я не могу воспользоваться этим.   -  person Phlucious    schedule 07.03.2013
comment
Унаследовать ModelResetter от QAsbtractItemModel тоже :D   -  person fasked    schedule 07.03.2013
comment
Умно, но разве это не нарушает почти все правила is-a идеи наследования?   -  person Phlucious    schedule 08.03.2013
comment
возможно, вы могли бы сделать свой ModelResetter вложенным классом в вашей модели. Затем вы можете использовать защищенные методы   -  person spiritwolfform    schedule 08.03.2013
comment
Я рассматривал такой вариант. Хотя я предпочитаю писать более обобщенно.   -  person Phlucious    schedule 08.03.2013
comment
См. мое редактирование для примера реализации шаблона. Я еще не до конца понимаю шаблоны.   -  person Phlucious    schedule 08.03.2013


Ответы (2)


вы можете сделать так, чтобы ваша унаследованная модель выставляла методы, которые просто вызывали бы beginResetModel() и endResetModel() соответственно, а затем ModelResetter вызывал бы эти методы.

person EHuhtala    schedule 08.03.2013
comment
Тогда нет ли у меня возможности написать класс ModelResetter таким образом, чтобы он использовал стандартную реализацию базового класса модели qt? - person Phlucious; 08.03.2013
comment
Ваша унаследованная модель публично наследуется? - person EHuhtala; 08.03.2013
comment
pastebin.com/NFuHpB8c компилируется для вас? это делает для меня на clang. Если это так, то кажется, что вы можете сделать ModelResetter другом MyModel, а затем напрямую вызвать beginResetModel()... У вас есть сообщение об ошибке, что он не работает? - person EHuhtala; 08.03.2013
comment
Да, это компилируется. Однако, следуя вашему примеру, я бы предпочел реализовать class Op его более обобщенным образом, чтобы он принимал Base*, и я мог применить его к другим моделям, а не только к той, которую я реализовал на данный момент. - person Phlucious; 08.03.2013
comment
можете ли вы сделать оболочку для Base, единственной целью которой является экспорт необходимой функции для Op? Затем все необходимые производные братья и сестры расширяются из этой оболочки. - person EHuhtala; 08.03.2013

Ненавижу отвечать на свой вопрос, но через пару дней я собрал решение на основе шаблона, которое отвечает всем моим требованиям. Yay для моего первого класса шаблонов с нуля. Вот реализация:

//modelresetter.h
#include <QAbstractItemModel>

/* you must declare this class as a friend to your model
 * to give it access to protected members as follows:
 * template <class Model> friend class ModelResetter;
 */
template<class Model>
class ModelResetter
{
public:
    ModelResetter(Model* model) : m_model(model)
    {
        Q_ASSERT_X(qobject_cast<QAbstractItemModel*>(model) != 0, __FUNCTION__,
                   "templated object does not inherit QAbstractItemModel");
        m_model->beginResetModel();
    }
    ~ModelResetter()
    {
        m_model->endResetModel();
    }

private:
    Model* m_model;
};

и использование:

//mymodel.cpp
bool MyModel::overhaul()
{
    ModelResetter<MyModel> resetter(this); resetter;  //prevent compiler warning

    //do stuff
    if(somethingswrong)
        return false; //model will finish reset at every exit point

    //do more stuff
    return true; //model also completes reset on success
}

Спасибо за вашу помощь!

person Phlucious    schedule 08.03.2013