Название: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 07, 2012, 19:00 Есть довольно интересная иерархия виджетов, есть базовый виджет от которого наследуются остальные. В базовом виджете должны проверяться некоторые условия, и если они валидны, то должна вызваться ф-цтя init() естественно в базовом виджете она виртуальная, а у наследников переопределена. Для решения этой задачи я накидал следующий код
widget.h Код: #ifndef WIDGET_H widget.cpp Код: #include "widget.h" и main.cpp Код: #include <QtGui/QApplication> компилятор хавает код нормально, а вот линкер ругается на Код: debug/main.o:main.cpp:(.rdata$_ZTV6WidgetI10LastWidgetE[vtable for Widget<LastWidget>]+0xe8): undefined reference to `Widget<LastWidget>::init()' стало быть возникают два вопроса, почему ругается ? и как победить ? полный пример прилагаю (в аттаче) Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 07, 2012, 20:33 Я обычно шаблонами вообще не пользуюсь, но тут возникла след. задача. Нужно для приложения реализовать два интерфейса
1. под винду и написан на декларативе (qml) 2. под мак нативный Стало быть я и сделал 1 базовый класс. который проверяет ос, и если это винда то создает дикларативный вьювер, если это мак то вызывает функцию init() в которой и будет происходить создание виджета под мак. вот ХЗ как это было по другому сделать :) А пример ваш работает, спасибо :) Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 07, 2012, 20:53 так и есть, но это здесь такое поведение если винда то интерфейс на декларативе если мак то нативный, стало быть базовый виджет все это проверяет и если нужно вызывает init для мака
Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 07, 2012, 21:09 Конструктор базового виджета
Код: template <typename Derived> коли под виндой мы, создаем на видете декларатив и принимаем qml, коли под маком мы для потомка вызываем init() который создает нативные компоненты. Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 07, 2012, 21:58 Не совсем, эта конструкция появилась по той причине, что для каждого наследника нужно вызвать init() , в шаблоне передаем наследника, и для него по необходимости вызывается init() - то есть создаются нужные компоненты, если без этой конструкции то нужно было бы у каждого виджета проверять на ос и т.д. (то что происходит в базовом виджете), копипаст меня не радует.
Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 08, 2012, 17:55 ИМХО, это плохой стиль. Обычно подобные конструкции свидетельствуют об архитектурных ошибках правда? :oклассики негодуют: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 08, 2012, 19:00 Остаюсь при своём мнении. и это правильно. вот только оглашать этого не надо. глупо выказывать свою не_эрудированность/не_образованность ;)Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 09, 2012, 18:47 ты совершенно прав.
но сам себя-то ты и не приметил, называя один из паттернов кривым стилем, ты считаешь себя умнее классиков. Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 09, 2012, 19:14 Цитировать Тот, кто следует шаблонам, никогда не создаст ничего нового. школота атакует ;Dи много нового ты создал чтоб тебя где-то публиковали? ты кем-то/где-то/в_чем-то признанный эксперт? ну хоть в чем-то? хоть в выращивании плесени? ;D Александреску/Саттер тебе не ровня, естественно. и не ты себя считаешь умнее других :facepalm Название: Re: Выполнить init() всем потомкам класса Отправлено: Igors от Март 09, 2012, 19:31 Конструкция template "на себя" возможна, хотя я ее пользовал всего раз или 2. На мой взгляд основной минус template - капитально затрудняется понимание. Вот и здесь - я честно прочитал тему минимум дважды, посмотрел исходники, в них все понятно. Но, убей бог, я совершенно не понял ЗАЧЕМ же нужен этот template, т.е. почему нельзя обойтись виртуалом :)
2kyv есть "особи" с которыми лучше не разговаривать вообще (следуя правилу зоны). Если разговор сваливается в дешевые понты (типа "ты не знаешь а вот Я знаю!") - то незачем отвечать такому (вернее "такой") Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 09, 2012, 19:52 мальчик тоньше нужно быть! тоньше! ;Dоставляю последнее слово за тобой ох как же это дешево. ни ума ни фантазии....Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 09, 2012, 19:54 2kyv есть "особи" с которыми лучше не разговаривать вообще (следуя правилу зоны). Если разговор сваливается в дешевые понты (типа "ты не знаешь а вот Я знаю!") - то незачем отвечать такому (вернее "такой") маладца! иди отмалчивайся в тряпочку. я дам знать когда тебе будет позволено открыть рот ;)Название: Re: Выполнить init() всем потомкам класса Отправлено: Sahab от Март 09, 2012, 20:06 Обычно подобные конструкции свидетельствуют об архитектурных ошибках. Да ну? Вы вообще давно с программированием связаны? Цитировать 1) Тот, кто следует шаблонам, никогда не создаст ничего нового. А также напишет очень много бажных-никому-не-нужных велосипедов.Название: Re: Выполнить init() всем потомкам класса Отправлено: niXman от Март 09, 2012, 20:07 я совершенно не понял ЗАЧЕМ же нужен этот template, т.е. почему нельзя обойтись виртуалом :) можно увидеть пример?Название: Re: Выполнить init() всем потомкам класса Отправлено: Igors от Март 09, 2012, 20:42 Цитировать 1) Тот, кто следует шаблонам, никогда не создаст ничего нового. А также напишет очень много бажных-никому-не-нужных велосипедов.Название: Re: Выполнить init() всем потомкам класса Отправлено: Sahab от Март 09, 2012, 20:59 Цитировать Если "шаблон" употреблено в широком смысле (ведь это не обязательно "template") Именно это я и имел в виду.Цитировать И уж лучше велосипед (со всеми его багами) чем "вычитанная умность" Спорно. Ко всему конечно нужно подходить с умом, однако девелопер потратит время, оплачиваемое кстати, на написание велосипеда (со всеми его багами). И не факт, что велосипед будет работать лучше и качественнее. Цитировать которая не проверена на себе. А что мешает ее проверить?Название: Re: Выполнить init() всем потомкам класса Отправлено: Sahab от Март 09, 2012, 21:03 Взять к примеру паттерны банды четырех. Хотите сказать, что это "неправильная умность" и не нужно их использовать?
А ведь с ними можно такую жесть наворотить, если их неправильно применять. Название: Re: Выполнить init() всем потомкам класса Отправлено: Igors от Март 09, 2012, 21:38 Спорно. Ко всему конечно нужно подходить с умом, однако девелопер потратит время, оплачиваемое кстати, на написание велосипеда (со всеми его багами). Хмм.. не всегда платят "за время" иногда и "за результат" (свои плюсы-минусы)И не факт, что велосипед будет работать лучше и качественнее. По сравнению с чем? Откуда уверенность что есть уже готовое решение для любой задачи? Это для студентов ("как сделать правельно"), а для реальных задач... Часто кажется - ну вот же, иногда сам это уже делал. Но при ближайшем рассмотрении выплывают "детали" - которые казались мелкими/незначительными, но, оказывается, они все меняют. И вот тут с (за)Знайками большие проблемы. Сначала у них срабатывает рефлекс на "написано" (как в опытах Павлова). Невозможно отговорить такого, все, он "знает". Но потом выясняется что это "не совсем то", а еще потом - "совсем не то". Тогда начинается претензии к постановке задачи, скандалы и.т.п. Ведь "делать самому" - позорно. Увы, таков часто результат обильных знаний и обширной эрудиции. Название: Re: Выполнить init() всем потомкам класса Отправлено: Akon от Март 11, 2012, 08:31 ТС: Конкретно по коду, ваша ошибка заключается в том, что у шаблона класса Widget<T> функция init объявлена, но не определена. Например, если сделаете ее чисто виртуальной, ошибка будет снята.
Код: template<typename Derived> Я так понимаю, вы хотите сделать т.н. "статический полиморфизм" для вызовов функций приватного класса, в частности, init(). Тогда зачем эта функция виртуальная? Ваш код мне не совсем понятен - в чем смысл приватного класса, если от него идет открытое наследование? Где в коде вызывается init()?. Просьба, опишите задачу более подробно. Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 11, 2012, 09:05 Должен быть примерно след. шаблон http://liveworkspace.org/code/e679e6c4df8079a5303dce4c027d048a приватный класс который есть в коде сделан только за счет того что классы с Q_OBJECT не поддерживают работу с шаблонами, а так как всетаки нужны сигналы и слоты пришлось извратиться написав приватный класс. Вопрос на самом деле уже решен, только из топика половина ответов прибито. В аттач выложу последний рабочий код. А задача стояла в том что бы под разными платформами рисовать разный интерфейс под маком нативный под виндой и линухом декларатив.
Название: Re: Выполнить init() всем потомкам класса Отправлено: Akon от Март 11, 2012, 10:20 Приведенный по ссылке шаблон (как есть) нерабочий в принципе, в смысле не соответствует задуманному. Вызов виртуального метода из конструктора - только не для С++! Желаемого поведения можно добиться, в частности, с помощью CRTP (одну из форм вы привели выше), но это потенциально бажный путь, поскольку наследник в общем случае не будет полностью создан. В С++ такая задача решается выделением полиморфного функционала в отдельный класс и использованием стратегии (паттерн).
Цитировать А задача стояла в том что бы под разными платформами рисовать разный интерфейс под маком нативный под виндой и линухом декларатив. Ну, типичная задача. А чем не устраивает подход, используемый в Qt (бридж)? Что в вашем случае дают шаблоны - элегантность, гибкость, меньший набор исходного кода, быстродействие?Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 11, 2012, 10:25 Наверное не совсем представляю что за Qt (бридж) поэтому и решил сделат как есть. Если можно пример буду рад
Название: Re: Выполнить init() всем потомкам класса Отправлено: Akon от Март 11, 2012, 10:48 Мост (Bridge) - широко используемый паттерн (описан в банде четырех), когда необходим единый интерфейс (паблик класс) для нескольких реализаций (приватный класс). Для примеров см. сорцы Qt, например, qwidget*.
Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 11, 2012, 10:48 Спасибо, гляну этот паттерн
Название: Re: Выполнить init() всем потомкам класса Отправлено: Igors от Март 11, 2012, 11:15 Неясно как в данном случае должен выглядеть этот мост, и не натолкнется ли он на проблемы с QObject и/или делегирование окажется слишком массивным. Вообще непонятно почему нельзя отделаться #ifdef ?
Название: Re: Выполнить init() всем потомкам класса Отправлено: ecspertiza от Март 11, 2012, 11:17 можно отделаться #ifdef , только придется в каждом виджете это проверять, а так проверка происходит только в одном месте :)
|