Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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.007 c
2-1216797045
Dimich1978
2008-07-23 11:10
2008.08.31
Открытие файла с изменение полей в WORDе


2-1216835667
valer4
2008-07-23 21:54
2008.08.31
try..finally


1-1198005654
Punch
2007-12-18 22:20
2008.08.31
MDI и мерцания MDIChild


15-1215708563
Nodt
2008-07-10 20:49
2008.08.31
Собираю машину.


2-1216805272
DFT
2008-07-23 13:27
2008.08.31
EPrivilege





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский