Форум: "Прочее";
Текущий архив: 2008.08.31;
Скачать: [xml.tar.bz2];
Вниз
CALLBACk процедура как часть класса в С++ Найти похожие ветки
← →
@!!ex © (2008-07-10 00:14) [0]Можно ли?
Суть в том, что надо реализовать подход к событиям аля дельфи.
Когда есть главвный класс, у него куча мемберов, которые должны вызывать CALLBACK функции из главного класса.
Теоретически это точно возможно, а вот как это реализовать практически - не представляю...
← →
Simpsons (2008-07-10 00:21) [1]А если через события? WM_USER + X?
← →
@!!ex © (2008-07-10 00:23) [2]> [1] Simpsons (10.07.08 00:21)
Классы - не обязательно окна и не обязательно под виндой.
← →
guav © (2008-07-10 00:28) [3]Теоретически: есть pointer-to-member-function. Запоминаешь его плюс укзатель на сам класс - вот и событие. Смотри операторы ->* и .* , оттуда найдёшь.
Практически: событие - переменная типа boost::function<R(P)>, обработчик - метод оборачивается в boost::bind, вторым параметром бинда this, далее другие параметры и плейсхолдеры.
← →
@!!ex © (2008-07-10 00:33) [4]> [3] guav © (10.07.08 00:28)
Теоретическую часть я понял, а вот практическую - нет. У меня нету boost и в MSDN найти не могу.
С указателем на класс проблем нету.
Он у всех мемберов как Parent прописан.
А вот как получить указатель на функцию?
← →
guav © (2008-07-10 00:45) [5]> [4] @!!ex © (10.07.08 00:33)
> У меня нету boost и в MSDN найти не могу.
А ведь в MSDN уже есть. Это часть будущего стандарта.
http://msdn.microsoft.com/en-us/library/bb982702.aspx
http://msdn.microsoft.com/en-us/library/bb982519.aspx
> А вот как получить указатель на функцию?struct X
{
int m1(char)
{
puts("hello");
return 42;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
int (X::*pM)(char);
X *pX;
X x;
pX = &x;
pM = &X::m1; // здесь.
return (pX->*pM)("z");
}
← →
Канадец (2008-07-10 00:46) [6]См. Observer design pattern. В частности реализации для C++.
← →
@!!ex © (2008-07-10 00:54) [7]> [5] guav © (10.07.08 00:45)
Как сделать вот в таком случае:void* Test = NULL;
void* Class = NULL;
class cTest
{
cTest()
{
Class = this;
Test = /*??*/;
};
virtual void Method();
};
{
(cTest)Class->/*??*/;
};
?
← →
@!!ex © (2008-07-10 00:54) [8]> А ведь в MSDN уже есть. Это часть будущего стандарта.
У меня 2005, в нем и смотрю...
2008 руки не доходят поставить, а online - интернет не позволяет.
← →
guav © (2008-07-10 01:03) [9]> [8] @!!ex © (10.07.08 00:54)
Вообще сильно ли нужны "события как в Делфи" ?
> Когда есть главный класс, у него куча мемберов, которые
> должны вызывать CALLBACK функции из главного класса.
Почему бы не дать всем классам, вызывающим методы главного, ссылку на главный класс ?
> [7] @!!ex © (10.07.08 00:54)
никак.
тип pointer-to-member-function не совместим с void*, фактически это не совсем указатель, и его размер может быть больше void* (на MSVC размер у него больше размера void* при наличии виртуального наследования).
тут надо на шаблонах делать, а не на приведениях.
← →
wl © (2008-07-10 01:34) [10]ну так может методы сделать статическими и не париться с размерами указателей?
← →
wl © (2008-07-10 01:51) [11]а что это для 2008 FP требуется redistributable? там что нельзя статически всё линковать. в бусте кажется это возможно
← →
@!!ex © (2008-07-10 09:58) [12]> Вообще сильно ли нужны "события как в Делфи" ?
Ну вот смотрите:
Есть куча классок cLabel, cImage, cTrackBar, cButton и так далее.
Программистом создается куча окон типа форм в Delphi, например сMenuWindow.
События зачем нужны?
Создаем метод OnButtonClick в классе cMenuWindow. Нужно чтобы кнопка вызвала метод OnButtonClick.
Ссылками это разве решабельно?
← →
guav © (2008-07-10 12:48) [13]
> Ссылками это разве решабельно?
Просто я подумал, что все мемберы знают про лавный класс, тогда хватило бы ссылки на него.
В данном случае, я бы делал смотря по ситуации.
события boost::signal
события boost::function
без событий.
Не хочешь буст - смотри другие слот-сигнальные примеры, их хватает.
http://rsdn.ru/article/cpp/delegates.xml
http://rsdn.ru/article/cpp/cxx_events.xml
Может ещё заинтересует применение колбэков как в С, через static метод, который принимает экземпляр класса, и оттуда уже вызывать обычный.
← →
@!!ex © (2008-07-10 12:56) [14]> [13] guav © (10.07.08 12:48)
Спасибо! Столько нового.... мозги пухнут...
Пока решил делать вот так:
Набор стандартных методов, ObButtonClick, ObImageBarPositionChange и т.д. в базовом классе
В качестве параметра - UID кнопки или другого объекта. В качестве UIDа может выступать указатель.
ТОгда в обработчике:
void cMyWindow::ObButtonClick(int ID)
{
switch(ID)
{
case 0: //первая кнопка
break;
case 1: //вторая кнопка кнопка
break;
//и т.д.
}
}
Насколько это приемлимо?
← →
guav © (2008-07-10 13:11) [15]> [14] @!!ex © (10.07.08 12:56)
> Насколько это приемлимо?
Настолько, насколько это будет работать. Я ж не дам рекомендаций на все случаи жизни :)
Чтобы не завязываться на конкретный главный класс и не вытворять чудеса на шаблонах, стоит сделать базовый класс с набором методов абстрактным базовым классом, т.е. интерфейсом: все методы pure virtual и пустой виртуальный деструктор, всё это public.
Кстати, Delphi при импорте объекта автоматизации для поддержки диспинтерфейса событий в IDispatch::Invoke ивент-синка генерит код вроде [14].
← →
guav © (2008-07-10 13:20) [16]> [11] wl © (10.07.08 01:51)
> а что это для 2008 FP требуется redistributable?
Подозреваю что то не redistributable к приложению, а пакет обновления к самой студии или redistributable для других улучшений этого пакета обновлений. А std::tr1::bind и std::tr1::function - header only, как и в бусте, ну нечего там в .cpp писать.
← →
GlFox © (2008-07-10 13:41) [17]> [15] guav © (10.07.08 13:11)
> Чтобы не завязываться на конкретный главный класс и не вытворять
> чудеса на шаблонах, стоит сделать базовый класс с набором
> методов абстрактным базовым классом, т.е. интерфейсом: все
> методы pure virtual и пустой виртуальный деструктор, всё
> это public.
Правда, лучше, пожалуй, не придумаешь.
Класс, функция которого должна вызываться по указателю, реализовывает определенный интерфейс.
А вместо указателя на функцию передаем указатель на экземпляр класса реализовывающий определенный интерфейс.
Все просто и без лишних заморочек.
← →
wl © (2008-07-10 13:54) [18]
> guav © (10.07.08 13:20) [16]
нет, есть FP на 330 мег, и есть FP redist на 4 мега.
я уже скачал посмотреть - там библиотеки MFC9.0.
кстати там же есть шаблоны для MFC, чтобы сделать меню в виде риббона, стиль офиса 2007. Выглядит забавно (хотя возможно это и до FP было, не обращал внимания).
← →
@!!ex © (2008-07-10 14:12) [19]
// CallbackTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class cButton;
class cCallbackInterface
{
// да, пустой интерфейс =)
// но виртуальная таблица существует
};
class cMainWnd : public cCallbackInterface
{
// этот класс наследует интерфейс, но не реализует логику на реакцию дочек.
};
typedef int (cCallbackInterface::*Tpf)(cButton*);
class cButton
{
private:
cMainWnd* m_Parent;
Tpf m_Action;
public:
cButton (cMainWnd* pParent, Tpf pf)
: m_Parent (pParent)
, m_Action (pf)
{
}
void Click ()
{
if (m_Parent)
{
(m_Parent->*m_Action) (this);
}
}
};
class cGameMainWnd : public cMainWnd
{
// а вот этот класс пусть уже реализует логику
public:
cButton* m_NewGameButton;
cButton* m_QuitButton;
void CreateWnd()
{
m_NewGameButton = new cButton (this, (Tpf)&cGameMainWnd::onNewButtonClick);
m_QuitButton = new cButton (this, (Tpf)&cGameMainWnd::onQuitButtonClick);
}
int onNewButtonClick (cButton* caller)
{
std::cout << "OnNewGame\n";
return 0;
}
int onQuitButtonClick (cButton* caller)
{
std::cout << "OnQuitGame\n";
return 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
cGameMainWnd m;
m.CreateWnd();
m.m_NewGameButton->Click();
m.m_QuitButton->Click();
return 0;
}
← →
@!!ex © (2008-07-10 14:19) [20]Код написан человеком, который теоретически мой подчиненный...
Меня учат мои подчиненные... *бьется головой об стенку*
← →
guav © (2008-07-10 15:05) [21]Я уже говорил, почему это не легально.
Хотя в MSVC действительно работает, если не использовать виртуальное наследование.
← →
@!!ex © (2008-07-10 15:55) [22]> [21] guav © (10.07.08 15:05)
Перечитал все внимательно. Думаю опять...
Уже 3 или 4 метод отметается.... :)
Спасибо за активное участие!
← →
31512 © (2008-07-10 15:59) [23]Поставь уже Qt и не мучайся.
← →
@!!ex © (2008-07-10 16:03) [24]> [23] 31512 © (10.07.08 15:59)
Обана, а он умеет работать с OpenGL?
← →
wl © (2008-07-10 16:26) [25]умеет. посмотреть пример можно например тут:
Ж. Бланшет, М. Саммерфилд. QT4: Программирование GUI.djvu
страница 234, QGLWidget
← →
guav © (2008-07-10 16:34) [26]Пример виртуального наследования:
struct X {};
struct Y {};
struct Z : X, virtual Y {};
int _tmain(int argc, _TCHAR* argv[])
{
typedef void (X::*P1)(void);
typedef void (Z::*P2)(void);
printf("%d %d\n", sizeof(P1), sizeof(P2));
return 0;
}
← →
wl © (2008-07-10 16:37) [27]а где можно почитать вкратце описание виртуального наследования? хочу понять область применения, никогда раньше не сталкивался, даже в литературе
← →
guav © (2008-07-10 16:43) [28]Я синтаксис по MSDN изучал.
http://msdn.microsoft.com/en-us/library/wcz57btd(VS.71).aspx
http://msdn.microsoft.com/en-us/library/9bzywxkx(VS.71).aspx
Пименяется там, где множественное наследование приводит к тому, что без виртуального наследования некоторые базы повторяются.
← →
31512 © (2008-07-11 10:24) [29]
> @!!ex © (10.07.08 16:03) [24]
Qt это, разумеется, не VCL. Но похожа (пусть только и внешне) на него очень. Даже релизовали MVC, что является огромным плюсом. Работает не только с OpenGL. С её системой слот/сигнал тебе callback просто нафиг не нужен будет. Ты вообще от системы зависеть не будешь. Есть свои ньюансы, разумеется, но она хорошо документирована.
← →
Zeqfreed © (2008-07-11 10:28) [30]Есть libsigc++ — Typesafe callback system for standard C++
← →
@!!ex © (2008-07-11 10:32) [31]Наш программист сказал, что делегаты - это то что нам нужно.
Брать чужие разработки смысла нет, у нас уже есть редактор VCL подобный, набор компонентов.
Только callback еще не работает.
← →
guav © (2008-07-11 11:34) [32]> [31] @!!ex © (11.07.08 10:32)
> Брать чужие разработки смысла нет, у нас уже есть редактор
> VCL подобный, набор компонентов.
Не понимаю. Почему бы не взять готовое слот-сигнальное решение, если действительно нужны делегаты. Boost.Signals например.
> m_NewGameButton = new cButton (...);
> m_QuitButton = new cButton (...);
Вот здесь, например, сильно желательны смарт-поинтеры. Причём, как и во многих случаях, скорее будут нужны scoped_ptr или shared_ptr, а не std::auto_ptr. Тоже свой велосипед изобретать будете ?
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2008.08.31;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.006 c