Russian Qt Forum
Ноябрь 23, 2024, 14:56 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Вопрос по ООП: расширение функциональности QAbstractItemView.  (Прочитано 10286 раз)
Akon
Гость
« Ответ #15 : Июль 27, 2012, 15:37 »

Цитировать
Под дополнительной функциональностью я подразумевал манипуляции с самим абстрактным вью, который потом должен превратится в конкрентую реализацию либо QTableView либо QTreeView.
Это требует доступ к протектед интерфейсу QAbstractItemView.

То, что предлагает Igors, называется "декоратор" (паттерн такой). Он вам не подходит, поскольку позволяет декорировать только паблик интерфейс QAbstractItemView.

Вот это
Цитировать
//NOTE: T is some Q...View class
template<typename T>
class myMegaView:public T{
//some shared code
называется миксином (mixin - подмешиваемая функциональность) и основывается на одной из форм CRTP (идиома C++ такая, см. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
Оно будет работать.
Достоинство - есть доступ к протектед интерфейсу.
Недостатки: 1. инстанцирование под каждый наследуемый тип, т.е. раздувание объектного кода (несущественный недостаток), 2. не будет отдельного интерфейса, который соответствует подмешанной функциональности (существенный недостаток, если такой интерфейс требуется); данный недостаток устраняется, путем создания интерфейса и наследования от него, имплементацию интерфейса делает миксин.

Вариант от kambala (класс Common).
Достоинства/недостатки - инверсия предудущего варианта.
Цитировать
Все хорошо пока вам в собственном методе data() не придется использовать методы QAbstractItemView.
Если из класса Common нужно обращение к паблик интерфейсу QAbstractItemView, то делается кросскаст.
Код:
class Common
{
public:
    QVariant data(const QModelIndex &index, int role) const
    {
        QAbstractItemView* thisAsQAbstractItemView = dynamic_cast<QAbstractItemView*>(this);
        thisAsQAbstractItemView->someMethod(...);
    }
};
В частности, кросскастом из Common к QObject можем выбросить любой сигнал из Common (разумеется, окончательный класс должен иметь такой сигнал):
Код:
void Common::setSomeProperty(int value)
{
if (value_ == value) return;
value_ = value;

QObject* object = dynamic_cast<QObject*>(this);  // crosscast
Q_ASSERT(object && "dynamic_cast<QObject*>(this)");

bool ok = QMetaObject::invokeMethod(object, "somePropertyChanged", Qt::DirectConnection,
QGenericReturnArgument(), Q_ARG(int, value));
Q_ASSERT(ok);
Q_UNUSED(ok);
}

Опять таки, в данном варианте нет доступа к протектед интерфейсу QAbstractItemView.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Июль 27, 2012, 16:07 »

То, что предлагает Igors, называется "декоратор" (паттерн такой). Он вам не подходит, поскольку позволяет декорировать только паблик интерфейс QAbstractItemView.
...
Опять таки, в данном варианте нет доступа к протектед интерфейсу QAbstractItemView.
Может и не подходит (на то и обсуждаем), но аргументацию не понял - если унаследоваться от QAbstractItemView, то protected методы доступны, и методы хранимого указателя тоже
Записан
ksergey85
Гость
« Ответ #17 : Июль 27, 2012, 16:59 »

Шаблонные классы и миксин не подходит из-за ограничений moc.
Кросс-каст интересная тема, но в этом случае класс не будет порожден от QObject и рассчитывать на сигналы и слоты похоже также не приходится? Сигналы и слоты в дополняющем интерфейсе я создать не смогу?
« Последнее редактирование: Июль 27, 2012, 17:03 от ksergey85 » Записан
Akon
Гость
« Ответ #18 : Июль 30, 2012, 07:16 »

Цитировать
Может и не подходит (на то и обсуждаем), но аргументацию не понял - если унаследоваться от QAbstractItemView, то protected методы доступны, и методы хранимого указателя тоже
Не понял мысль. Протектед интерфейс не доступен через композицию (QAbstractItemView* view_;).

Цитировать
Шаблонные классы и миксин не подходит из-за ограничений moc.
Кросс-каст интересная тема, но в этом случае класс не будет порожден от QObject и рассчитывать на сигналы и слоты похоже также не приходится? Сигналы и слоты в дополняющем интерфейсе я создать не смогу?

Ограничения moc не приятны, было бы хорошо, если бы поддерживалось множественное наследование от QObject. Тем не менее, проблема решается следующим образом: сигналы не объявляются в шаблонных классам, миксинах или в других базовых классах (Common). Сигналы могут объявляться только там где будет Q_OBJECT, т.е. в вашем окончательном классе (классах). Тем не менее, из упомянутых мест сигналы можно выбрасывать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Июль 30, 2012, 10:26 »

Не понял мысль. Протектед интерфейс не доступен через композицию (QAbstractItemView* view_;).
А если композитор и сам наследует QAbstractItemView ? (т.е. как бы 2 паттерна в одном). Может где-то заклинит, но рассмотреть стоит.
Записан
ksergey85
Гость
« Ответ #20 : Июль 30, 2012, 10:46 »

Хорошо с сигналами слотами потерпеть можно, не так их и много получается. В конце концов приоритетной является задача общего интерфейса.
Пока реализовывал методы с помощью кросскаста возникла проблема. В своем Common перекрыл виртуальный метод setModel() класса QAbstractItemView, но этот метод перекрывают и конкретные реализации, т.е. у классов QTableView и QTreeView он свой. Как мне добраться именно до QTableView::setModel() и QTreeView::setModel().

Имею в Common::setModel(QAbstractItemModel *model)
QAbstractItemView* thisAsView = dynamic_cast<QAbstractItemView*>(this); //crosscast
thisAsView->setModel(model); //вызов самого себя - рекурсия нам не нужна
thisAsView->QAbstractItemView::setModel(model); //статически слинкует с методом класса QAbstractItemView.

Как добраться до перегруженного метода? И реально ли это вообще? Непонимающий
« Последнее редактирование: Июль 30, 2012, 12:19 от ksergey85 » Записан
Akon
Гость
« Ответ #21 : Июль 30, 2012, 13:10 »

Цитировать
А если композитор и сам наследует QAbstractItemView ? (т.е. как бы 2 паттерна в одном). Может где-то заклинит, но рассмотреть стоит.
В этом суть декоратора - внешний интерфейс тот-же, а поведение изменено (с меньшей связностью, нежели при открытом наследовании). Но, повторяю, вы не сможете получить доступ к протектед интерфейсу.

Цитировать
В своем Common перекрыл виртуальный метод setModel() класса QAbstractItemView
Это не перекрытие (виртуального метода). Это создание другого метода. Метод перекрыть можно только из наследника.

Код:
thisAsView->setModel(model); //вызов самого себя - рекурсия нам не нужна
Счего взяли? Это не рукурсия, это полиморфный вызов QAbstractItemView::setModel(). После кросскаста фактическое значение указателя будет другим - соответствующим положению QAbstractItemView в составном классе, соответственно, VMT будет восходить к QAbstractItemView. Кстати, еще ограничение мока - база QObject должна быть первой.

Если знакомы с COM или какой-либо подобной технологией, то кросскаст это аналог QueryInterface().
« Последнее редактирование: Июль 30, 2012, 13:33 от Akon » Записан
ksergey85
Гость
« Ответ #22 : Июль 30, 2012, 13:48 »

Все догнал. То есть по сути виртуальные методы из Common после такого кросс-каста становятся вообще не в счет? У них своя отдельная VMT?
Интересно только как я вызовом thisAsView->setModel(model) мог получить рекурсию при отладке. Но это не важно. Скорее всего дело в том, что мой метод принимает указатель не на объект QAbstractItemModel, а на объект класса-наследника.
P.S. бьюсь над тем как бы покорректнее внедрить слоты и сигналы в Common.
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.116 секунд. Запросов: 23.