Название: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:01 Здравствуйте. Бьюсь над таким вопросом. Он скорее из области ООП, но имеет отношение и Qt.
Имеем два стандартных Qt-шных класса QTableView и QTreeView, порожденных от одного абстрактного предка QAbstractItemView. Возникла необходимость добавить некоторую функциональность, которая имеет одинаковую реализацию как для QTableView так и для QTreeView. Естественно два раза писать одинаковые методы, перекрыв классы QTableView и QTreeView не хочется. Я перекрываю общего родителя QAbstractItemView, дополняю класс нужной мне функциональностью, и теперь мне необходимо перенести эту дополнительную функциональность в оба дочерних неабстрактных класса с помощью механизма наследования. Как я могу это сделать? В данный момент блуждаю около виртуального множественного наследования, наступил на такие грабли: классы QTableView и QTreeView порождены от QAbstractItemView не виртуально, поэтому никак не выходит заставить компилятор создать только одну копию класса QAbstractItemView, чтобы он перестал ругаться о неоднозначностях при использовании методов QAbstractItemView. Как я понимаю в ObjectiveC для подобных ситуаций придуманы категории. Что тут можно придумать на плюсах? Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: mutineer от Июль 27, 2012, 11:10 отнаследовать QTableView и QTreeView от твоего класса, вместо QAbstractItemView. Ну и на обычнах Qt либах это работать не будет - придется делать либо статическую сборку, либо везде носить собственную версию Qt либ с собой
Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Igors от Июль 27, 2012, 11:14 Ну делаете QAbstractItemView * членом Вашего класса и заряжаете его по обстановке QTableView* или QTreeView*. Чем не устраивает этот стандартный прием?
Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:24 Ну делаете QAbstractItemView * членом Вашего класса и заряжаете его по обстановке QTableView* или QTreeView*. Чем не устраивает этот стандартный прием? То есть имеете в виду композицию. Но тогда я не смогу напрямую обращаться к методам QAbstractItemView как к методам моего класса. Или не так?Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: kambala от Июль 27, 2012, 11:27 можно попробовать вынести одинаковую функциональность в отдельный класс и множественно наследоваться от этого класса и QTableView/QTreeView. должно получиться что-то типа такого:
Код вот только я не знаю как там будет с сигналами и метаобъектной системой в целом Ну делаете QAbstractItemView * членом Вашего класса и заряжаете его по обстановке QTableView* или QTreeView*. Чем не устраивает этот стандартный прием? То есть имеете в виду композицию. Но тогда я не смогу напрямую обращаться к методам QAbstractItemView как к методам моего класса. Или не так?Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:28 Похоже я все-таки нашел очень похожую тему: http://www.linux.org.ru/forum/development/4181710. Там решение удовлетворяющее меня частично найдено. Можно зафигачить шаблон класса, где и описать всю общую для классов функциональность.
Цитата: //NOTE: T is some Q...View class template<typename T> class myMegaView:public T{ //some shared code }; А свои виджеты наследуете так: class myWidget:public myMegaView<QTreeView>{ }; Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: DmitryM от Июль 27, 2012, 11:36 У шаблонных классов не может быть сигнал/слотов.
Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:47 To kambala:
Все хорошо пока вам в собственном методе data() не придется использовать методы QAbstractItemView. Под дополнительной функциональностью я подразумевал манипуляции с самим абстрактным вью, который потом должен превратится в конкрентую реализацию либо QTableView либо QTreeView. На счет оберток - я ж замучаюсь ко всем нужным мне методам писать обертки. И потом если мой класс не будет прямым наследником QAbstractItemView то я не смогу его использовать как полноценный вью там где Qt ожидает от меня вью. Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Igors от Июль 27, 2012, 11:52 То есть имеете в виду композицию. Но тогда я не смогу напрямую обращаться к методам QAbstractItemView как к методам моего класса. Или не так? Свой класс наследуете от QAbstractItemView, да, придется "делегироваться", может обильно. Ну ничего страшного, можно потерпеть Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:53 У шаблонных классов не может быть сигнал/слотов. Откуда информация? Можно ссылку?Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 11:57 То есть имеете в виду композицию. Но тогда я не смогу напрямую обращаться к методам QAbstractItemView как к методам моего класса. Или не так? Свой класс наследуете от QAbstractItemView, да, придется "делегироваться", может обильно. Ну ничего страшного, можно потерпеть Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 12:07 Кстати шаблоны не подходят. Сигналов/слотов не будет да. Он же вообще не будет наследником QObject :(
UPDATE: туплю - будет. Вопрос прежний почему не будут работать сигналы и слоты? Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Igors от Июль 27, 2012, 12:07 То есть мне нужно наследоваться от QAbstractItemView или все-таки сделать QAbstractItemView частью моего класса в виде член-данного? "и" (вместо "или")Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: DmitryM от Июль 27, 2012, 12:14 У шаблонных классов не может быть сигнал/слотов. Откуда информация? Можно ссылку?Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 12:16 То есть мне нужно наследоваться от QAbstractItemView или все-таки сделать QAbstractItemView частью моего класса в виде член-данного? "и" (вместо "или")Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Akon от Июль 27, 2012, 15:37 Цитировать Под дополнительной функциональностью я подразумевал манипуляции с самим абстрактным вью, который потом должен превратится в конкрентую реализацию либо QTableView либо QTreeView. Это требует доступ к протектед интерфейсу QAbstractItemView.То, что предлагает Igors, называется "декоратор" (паттерн такой). Он вам не подходит, поскольку позволяет декорировать только паблик интерфейс QAbstractItemView. Вот это Цитировать //NOTE: T is some Q...View class называется миксином (mixin - подмешиваемая функциональность) и основывается на одной из форм CRTP (идиома C++ такая, см. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)). template<typename T> class myMegaView:public T{ //some shared code Оно будет работать. Достоинство - есть доступ к протектед интерфейсу. Недостатки: 1. инстанцирование под каждый наследуемый тип, т.е. раздувание объектного кода (несущественный недостаток), 2. не будет отдельного интерфейса, который соответствует подмешанной функциональности (существенный недостаток, если такой интерфейс требуется); данный недостаток устраняется, путем создания интерфейса и наследования от него, имплементацию интерфейса делает миксин. Вариант от kambala (класс Common). Достоинства/недостатки - инверсия предудущего варианта. Цитировать Все хорошо пока вам в собственном методе data() не придется использовать методы QAbstractItemView. Если из класса Common нужно обращение к паблик интерфейсу QAbstractItemView, то делается кросскаст.Код: class Common Код: void Common::setSomeProperty(int value) Опять таки, в данном варианте нет доступа к протектед интерфейсу QAbstractItemView. Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Igors от Июль 27, 2012, 16:07 То, что предлагает Igors, называется "декоратор" (паттерн такой). Он вам не подходит, поскольку позволяет декорировать только паблик интерфейс QAbstractItemView. Может и не подходит (на то и обсуждаем), но аргументацию не понял - если унаследоваться от QAbstractItemView, то protected методы доступны, и методы хранимого указателя тоже... Опять таки, в данном варианте нет доступа к протектед интерфейсу QAbstractItemView. Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 27, 2012, 16:59 Шаблонные классы и миксин не подходит из-за ограничений moc.
Кросс-каст интересная тема, но в этом случае класс не будет порожден от QObject и рассчитывать на сигналы и слоты похоже также не приходится? Сигналы и слоты в дополняющем интерфейсе я создать не смогу? Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Akon от Июль 30, 2012, 07:16 Цитировать Может и не подходит (на то и обсуждаем), но аргументацию не понял - если унаследоваться от QAbstractItemView, то protected методы доступны, и методы хранимого указателя тоже Не понял мысль. Протектед интерфейс не доступен через композицию (QAbstractItemView* view_;).Цитировать Шаблонные классы и миксин не подходит из-за ограничений moc. Кросс-каст интересная тема, но в этом случае класс не будет порожден от QObject и рассчитывать на сигналы и слоты похоже также не приходится? Сигналы и слоты в дополняющем интерфейсе я создать не смогу? Ограничения moc не приятны, было бы хорошо, если бы поддерживалось множественное наследование от QObject. Тем не менее, проблема решается следующим образом: сигналы не объявляются в шаблонных классам, миксинах или в других базовых классах (Common). Сигналы могут объявляться только там где будет Q_OBJECT, т.е. в вашем окончательном классе (классах). Тем не менее, из упомянутых мест сигналы можно выбрасывать. Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Igors от Июль 30, 2012, 10:26 Не понял мысль. Протектед интерфейс не доступен через композицию (QAbstractItemView* view_;). А если композитор и сам наследует QAbstractItemView ? (т.е. как бы 2 паттерна в одном). Может где-то заклинит, но рассмотреть стоит.Название: Re: Вопрос по ООП: расширение функциональнос& Отправлено: ksergey85 от Июль 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. Как добраться до перегруженного метода? И реально ли это вообще? ??? Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: Akon от Июль 30, 2012, 13:10 Цитировать А если композитор и сам наследует QAbstractItemView ? (т.е. как бы 2 паттерна в одном). Может где-то заклинит, но рассмотреть стоит. В этом суть декоратора - внешний интерфейс тот-же, а поведение изменено (с меньшей связностью, нежели при открытом наследовании). Но, повторяю, вы не сможете получить доступ к протектед интерфейсу.Цитировать В своем Common перекрыл виртуальный метод setModel() класса QAbstractItemView Это не перекрытие (виртуального метода). Это создание другого метода. Метод перекрыть можно только из наследника.Код: thisAsView->setModel(model); //вызов самого себя - рекурсия нам не нужна Если знакомы с COM или какой-либо подобной технологией, то кросскаст это аналог QueryInterface(). Название: Re: Вопрос по ООП: расширение функциональности QAbstractItemView. Отправлено: ksergey85 от Июль 30, 2012, 13:48 Все догнал. То есть по сути виртуальные методы из Common после такого кросс-каста становятся вообще не в счет? У них своя отдельная VMT?
Интересно только как я вызовом thisAsView->setModel(model) мог получить рекурсию при отладке. Но это не важно. Скорее всего дело в том, что мой метод принимает указатель не на объект QAbstractItemModel, а на объект класса-наследника. P.S. бьюсь над тем как бы покорректнее внедрить слоты и сигналы в Common. |