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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Выполнить init() всем потомкам класса  (Прочитано 12335 раз)
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« : Март 07, 2012, 19:00 »

Есть довольно интересная иерархия виджетов, есть базовый виджет от которого наследуются остальные. В базовом виджете должны проверяться некоторые условия, и если они валидны, то должна вызваться ф-цтя init() естественно в базовом виджете она виртуальная, а у наследников переопределена. Для решения этой задачи я накидал следующий код


widget.h
Код:
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>

class WidgetPrivate : public QWidget
{
    Q_OBJECT

    public:
        WidgetPrivate(QWidget *parent = 0);


        void setSource(QString arg);

    signals:
        void created();


    private:
        QString m_source;

    private slots:
        void cr();
};

template<typename Derived>
class Widget : public WidgetPrivate
{
    public:
        Widget(Derived *d,QWidget *parent = 0);


    protected:
        void mousePressEvent(QMouseEvent *);
        virtual void init();
};

class FirstWidget : public Widget<FirstWidget>
{
    public:
        FirstWidget(QWidget *parent = 0);

        void init();
};

class LastWidget : public Widget<LastWidget>
{
    public:
        LastWidget(QWidget *parent = 0);

        void init();
};


#endif // WIDGET_H


widget.cpp
Код:
#include "widget.h"

WidgetPrivate::WidgetPrivate(QWidget *parent)
    :QWidget(parent)
{
    connect(this,SIGNAL(created()),this,SLOT(cr()));
    emit created();
}

void WidgetPrivate::cr()
{
    qDebug() << "create widget";
}

void WidgetPrivate::setSource(QString arg)
{
    m_source = arg;
}

template<typename Derived>
Widget<Derived>::Widget(Derived *d,QWidget *parent)
    :WidgetPrivate(parent)
{
    qDebug() << Q_FUNC_INFO;
}

template<typename Derived>
void Widget<Derived>::mousePressEvent(QMouseEvent *)
{
    qDebug() << Q_FUNC_INFO;
}

FirstWidget::FirstWidget(QWidget *parent)
    :Widget<FirstWidget>(this,parent)
{
    qDebug() << Q_FUNC_INFO;
}

void FirstWidget::init()
{

}

LastWidget::LastWidget(QWidget *parent)
    :Widget<LastWidget>(this,parent)
{
    qDebug() << Q_FUNC_INFO;
}

void LastWidget::init()
{
    setWindowTitle("Last");
}


и main.cpp
Код:
#include <QtGui/QApplication>
#include <QWidget>

#include <QDebug>

#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    FirstWidget f;
    f.setSource("f");
    f.show();

    LastWidget l;
    l.setSource("l");
    l.show();

    return a.exec();
}

компилятор хавает код нормально, а вот линкер ругается на

Код:
debug/main.o:main.cpp:(.rdata$_ZTV6WidgetI10LastWidgetE[vtable for Widget<LastWidget>]+0xe8): undefined reference to `Widget<LastWidget>::init()'
debug/main.o:main.cpp:(.rdata$_ZTV6WidgetI11FirstWidgetE[vtable for Widget<FirstWidget>]+0xe8): undefined reference to `Widget<FirstWidget>::init()'

стало быть возникают два вопроса, почему ругается ? и как победить ?

полный пример прилагаю (в аттаче)
Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #1 : Март 07, 2012, 20:33 »

Я обычно шаблонами вообще не пользуюсь, но тут возникла след. задача. Нужно для приложения реализовать два интерфейса
1. под винду и написан на декларативе  (qml)
2. под мак нативный

Стало быть я и сделал 1 базовый класс. который проверяет ос, и если это винда то создает дикларативный вьювер, если это мак то вызывает функцию init() в которой и будет происходить создание виджета под мак. вот ХЗ как это было по другому сделать Улыбающийся

А пример ваш работает, спасибо Улыбающийся
« Последнее редактирование: Март 07, 2012, 20:35 от ecspertiza » Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #2 : Март 07, 2012, 20:53 »

так и есть, но это здесь такое поведение если винда то интерфейс на декларативе если мак то нативный, стало быть базовый виджет все это проверяет и если нужно вызывает init для мака
Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #3 : Март 07, 2012, 21:09 »

Конструктор базового виджета

Код:
template <typename Derived>
BasicWindow<Derived>::BasicWindow(Derived *d,QWidget *parent)
    :BasicWindowPrivate(parent)
{
    #ifndef Q_OS_MAC || Q_OS_MACX || Q_OS_MAC64 || Q_OS_DARWIN || Q_OS_DARWIN64
        m_layout = new QVBoxLayout(this);
        m_layout->setMargin(0);
        m_layout->setSpacing(0);
        m_viewer = new QDeclarativeView(this);
        m_viewer->viewport()->installEventFilter(this);
        m_layout->addWidget(m_viewer);

        m_viewer->setResizeMode(QDeclarativeView::SizeRootObjectToView);
        m_viewer->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);

        m_viewer->rootContext()->setContextProperty("window",this);
        m_viewer->rootContext()->setContextProperty("core",Core::instance());

        QObject::connect(m_viewer->rootContext()->engine(), SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));

        m_viewer->setMouseTracking(true);
    #else
        m_viewer = NULL;
        d->setRoundRect(false);
        d->init();
    #endif

}

коли под виндой мы, создаем на видете декларатив и принимаем qml, коли под маком мы для потомка вызываем init() который создает нативные компоненты.
Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #4 : Март 07, 2012, 21:58 »

Не совсем, эта конструкция появилась по той причине, что для каждого наследника нужно вызвать init() , в шаблоне передаем наследника, и для него по необходимости вызывается init() - то есть создаются нужные компоненты, если без этой конструкции то нужно было бы у каждого виджета проверять на ос и т.д. (то что происходит в базовом виджете), копипаст меня не радует.
Записан
niXman
Гость
« Ответ #5 : Март 08, 2012, 17:55 »

ИМХО, это плохой стиль. Обычно подобные конструкции свидетельствуют об архитектурных ошибках
правда? Шокированный
классики негодуют: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Записан
niXman
Гость
« Ответ #6 : Март 08, 2012, 19:00 »

Остаюсь при своём мнении.
и это правильно. вот только оглашать этого не надо. глупо выказывать свою не_эрудированность/не_образованность Подмигивающий
Записан
niXman
Гость
« Ответ #7 : Март 09, 2012, 18:47 »

ты совершенно прав.
но сам себя-то ты и не приметил, называя один из паттернов кривым стилем, ты считаешь себя умнее классиков.
Записан
niXman
Гость
« Ответ #8 : Март 09, 2012, 19:14 »

Цитировать
Тот, кто следует шаблонам, никогда не создаст ничего нового.
школота атакует Смеющийся

и много нового ты создал чтоб тебя где-то публиковали?
ты кем-то/где-то/в_чем-то признанный эксперт? ну хоть в чем-то? хоть в выращивании плесени? Смеющийся

Александреску/Саттер тебе не ровня, естественно. и не ты себя считаешь умнее других :facepalm
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Март 09, 2012, 19:31 »

Конструкция template "на себя" возможна, хотя я ее пользовал всего раз или 2. На мой взгляд основной минус template - капитально затрудняется понимание. Вот и здесь - я честно прочитал тему минимум дважды, посмотрел исходники, в них все понятно. Но, убей бог, я совершенно не понял ЗАЧЕМ же нужен этот template, т.е. почему нельзя обойтись виртуалом   Улыбающийся

2kyv есть "особи" с которыми лучше не разговаривать вообще (следуя правилу зоны). Если разговор сваливается в дешевые понты (типа "ты не знаешь а вот Я знаю!") - то незачем отвечать такому (вернее "такой")
Записан
niXman
Гость
« Ответ #10 : Март 09, 2012, 19:52 »

мальчик
тоньше нужно быть! тоньше! Смеющийся

оставляю последнее слово за тобой
ох как же это дешево. ни ума ни фантазии....
Записан
niXman
Гость
« Ответ #11 : Март 09, 2012, 19:54 »

2kyv есть "особи" с которыми лучше не разговаривать вообще (следуя правилу зоны). Если разговор сваливается в дешевые понты (типа "ты не знаешь а вот Я знаю!") - то незачем отвечать такому (вернее "такой")
маладца! иди отмалчивайся в тряпочку. я дам знать когда тебе будет позволено открыть рот Подмигивающий
Записан
Sahab
Гость
« Ответ #12 : Март 09, 2012, 20:06 »

Обычно подобные конструкции свидетельствуют об архитектурных ошибках.
Да ну? Вы вообще давно с программированием связаны?

Цитировать
1) Тот, кто следует шаблонам, никогда не создаст ничего нового.
А также напишет очень много бажных-никому-не-нужных велосипедов.
« Последнее редактирование: Март 09, 2012, 20:15 от Sahab » Записан
niXman
Гость
« Ответ #13 : Март 09, 2012, 20:07 »

я совершенно не понял ЗАЧЕМ же нужен этот template, т.е. почему нельзя обойтись виртуалом   Улыбающийся
можно увидеть пример?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Март 09, 2012, 20:42 »

Цитировать
1) Тот, кто следует шаблонам, никогда не создаст ничего нового.
А также напишет очень много бажных-никому-не-нужных велосипедов.
Если "шаблон" употреблено в широком смысле (ведь это не обязательно "template") то я согласен. И уж лучше велосипед (со всеми его багами) чем "вычитанная умность", которая не проверена на себе. 
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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