Чайниковский вопрос по C++

Angry
Уже с Приветом
Posts: 1491
Joined: 02 Jul 2003 22:47

Чайниковский вопрос по C++

Post by Angry »

Задача стоит такая - реализовать механизм событий,
аналогичный в DELPHI.

Т.е. существует к примеру класс Cbutton, экземпляр которого
используется в наследнике классе СWindow, и нужно,
чтобы на событие OnClick экземпляра Cbutton вызывался
метод класса CWindow.

Проблема в том, что function pointer OnClick класса Cbutton должен
быть описан как метод какого-то конкретного класса, что неприемлимо,
т.к. неизвестно в каком классе он будет вызыватся.
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Re: Чайниковский вопрос по C++

Post by A. Fig Lee »

Angry wrote:Задача стоит такая - реализовать механизм событий,
аналогичный в DELPHI.

Т.е. существует к примеру класс Cbutton, экземпляр которого
используется в наследнике классе СWindow, и нужно,
чтобы на событие OnClick экземпляра Cbutton вызывался
метод класса CWindow.

Проблема в том, что function pointer OnClick класса Cbutton должен
быть описан как метод какого-то конкретного класса, что неприемлимо,
т.к. неизвестно в каком классе он будет вызыватся.

Не понял. Кто ето все будет писать - Вы?
Тогда самому можно и дописать функцию в СБаттон.
Иначе Можно иметь месседж мап в Виндовс и посылать месседж.
Вы на пальцах покажите где узкое место. А Делфи мы уж давно не помним.
Верить нельзя никому - даже себе. Мне - можно!
Angry
Уже с Приветом
Posts: 1491
Joined: 02 Jul 2003 22:47

Re: Чайниковский вопрос по C++

Post by Angry »

A. Fig Lee wrote:
Angry wrote:Задача стоит такая - реализовать механизм событий,
аналогичный в DELPHI.

Т.е. существует к примеру класс Cbutton, экземпляр которого
используется в наследнике классе СWindow, и нужно,
чтобы на событие OnClick экземпляра Cbutton вызывался
метод класса CWindow.

Проблема в том, что function pointer OnClick класса Cbutton должен
быть описан как метод какого-то конкретного класса, что неприемлимо,
т.к. неизвестно в каком классе он будет вызыватся.

Не понял. Кто ето все будет писать - Вы?
Тогда самому можно и дописать функцию в СБаттон.
Иначе Можно иметь месседж мап в Виндовс и посылать месседж.
Вы на пальцах покажите где узкое место. А Делфи мы уж давно не помним.


У разных экземпляров Cбаттон - разные обработчики в OnClick

Узкое место - если описано

class CSpriteAnimation2
{
public:
CSpriteAnimation2(LPDIRECT3DDEVICE9 m_Device,char *fname,char *ftexturename);
CSpriteAnimation2(LPDIRECT3DDEVICE9 m_Device,char *fname,LPDIRECT3DTEXTURE9 Texture);
~CSpriteAnimation2();

long (*function)(int i);
};

А потом
long CCustomPresentation::testf(int i)
{
CSpriteAnimation2 a(NULL,"1","2");
a.function=this->testf;
}

Выдает ошибку

Нессответствие типов 'long (__thiscall CCustomPresentation::* )(int)' to 'long (__cdecl *)(int)'

Возможно ли это обойти?
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Re: Чайниковский вопрос по C++

Post by A. Fig Lee »

Angry wrote:
A. Fig Lee wrote:
Angry wrote:Задача стоит такая - реализовать механизм событий,
аналогичный в DELPHI.

Т.е. существует к примеру класс Cbutton, экземпляр которого
используется в наследнике классе СWindow, и нужно,
чтобы на событие OnClick экземпляра Cbutton вызывался
метод класса CWindow.

Проблема в том, что function pointer OnClick класса Cbutton должен
быть описан как метод какого-то конкретного класса, что неприемлимо,
т.к. неизвестно в каком классе он будет вызыватся.

Не понял. Кто ето все будет писать - Вы?
Тогда самому можно и дописать функцию в СБаттон.
Иначе Можно иметь месседж мап в Виндовс и посылать месседж.
Вы на пальцах покажите где узкое место. А Делфи мы уж давно не помним.


У разных экземпляров Cбаттон - разные обработчики в OnClick

Узкое место - если описано

class CSpriteAnimation2
{
public:
CSpriteAnimation2(LPDIRECT3DDEVICE9 m_Device,char *fname,char *ftexturename);
CSpriteAnimation2(LPDIRECT3DDEVICE9 m_Device,char *fname,LPDIRECT3DTEXTURE9 Texture);
~CSpriteAnimation2();

long (*function)(int i);
};

А потом
long CCustomPresentation::testf(int i)
{
CSpriteAnimation2 a(NULL,"1","2");
a.function=this->testf;
}

Выдает ошибку

Нессответствие типов 'long (__thiscall CCustomPresentation::* )(int)' to 'long (__cdecl *)(int)'

Возможно ли это обойти?

Так. Вы смешали в кучу Сшные каллбеки и С++.
Мона сделать так - все баттоны должны быть деривед иот класса ВасяПупкин.
В классе Вася Пупкин имеем одну публи фанкшн которую и будем звать.
Тогда и присваивать ничего не надо?

class VasjaPupkin
{
public:
virtual void do_it(){/*do it here*/}
};

class MyButton1 : public VasjaPupkin
{
...
};

class MyButton2 : public VasjaPupkin
{
...
};

int do_any(VasjaPupkin *a)
{
a->do_it();
}

and you may call
do_any(new MyButton1)
{
}

Примерно так.
Верить нельзя никому - даже себе. Мне - можно!
Vovka
Уже с Приветом
Posts: 1906
Joined: 14 Mar 2001 10:01

Post by Vovka »

Действительно, как уже писал A. Fig Lee хотелось бы знать поконкретней вашу проблему.
Пока могу только догадываться, что раз вы не используете стандартные massage maps, которые есть практически по всех GUI библиотеках для Windows, вы имеете дело с собственным набором событий, а не со стандартными windows messages.
Тогда, возможно, вам лучше вообще по-другому сделать, и GUIные библиотеки (во всяком случае те, которые я знаю) здесь не очень хороший пример для подражания.
Возможно, вам подойдёт какая-нить вариация Observer Pattern.

Code: Select all


struct MouseObserver
{
  virtual void OnLButtonDown() = 0;
  ...
};

class Mouse
{
public:
  void Subscribe(MouseObserver * o)   {  m_obs.add(o);  }
  void Unsibscribe(MouseObserver * o)  { m_obs.remove(o); }

private:

  void FireLButtonDown()
  {
    for each o in m_obs
      o->OnLButtonDown();
  }

  ObsList m_obs; 
};

Vovka
Уже с Приветом
Posts: 1906
Joined: 14 Mar 2001 10:01

Re: Чайниковский вопрос по C++

Post by Vovka »

A. Fig Lee wrote: Мона сделать так - все баттоны должны быть деривед иот класса ВасяПупкин...


Как я понял, Angry хочет динамически управлять диспетчеризацией, раз вон указатели на ф-ции пытается присваивать во время выполнения?
Hamster
Уже с Приветом
Posts: 11475
Joined: 20 Nov 2000 10:01
Location: Escondido, CA

Post by Hamster »

Надо декларировать пойнтер как

Code: Select all

long (CSpriteAnimation2::*function)(int i); 

Если хотите вызывать функцию не для родительского объекта ( в первом примере, CButton не наследует от CWindow ), нужно еще сохранять указатель на объект.
User avatar
DenisM
Уже с Приветом
Posts: 1976
Joined: 08 Jun 1999 09:01
Location: SPb -> SFBA -> Beaverton, OR

Post by DenisM »

Hamster wrote:Надо декларировать пойнтер как

Code: Select all

long (CSpriteAnimation2::*function)(int i); 

Если хотите вызывать функцию не для родительского объекта ( в первом примере, CButton не наследует от CWindow ), нужно еще сохранять указатель на объект.

Angry, почитайте про Pointer-to-Member Operators, Hamster дело говорит.
Yuri_p33
Уже с Приветом
Posts: 394
Joined: 12 Feb 2001 10:01
Location: USA

Re: Чайниковский вопрос по C++

Post by Yuri_p33 »

Angry wrote:Задача стоит такая - реализовать механизм событий, аналогичный в DELPHI....Проблема в том, что function pointer OnClick класса Cbutton должен быть описан как метод какого-то конкретного класса, что неприемлимо, т.к. неизвестно в каком классе он будет вызыватся.
Вот вам примерчик. Писалось на коленке, так что не ругайте. Старался сделать как можно больше похоже на Делфи, для аналогий.

Code: Select all

#include "stdafx.h"

class TNotifyEvent
{
public:
   virtual void Call(void *sender) = 0;
};

template<class T> class TTNotifyEvent: public TNotifyEvent
{
typedef void (T::*_NotifyFuncPtr)(void *);
private:
   T *m_target_obj;
   _NotifyFuncPtr m_target_obj_func;
public:
   TTNotifyEvent(T *target, _NotifyFuncPtr func): m_target_obj(target), m_target_obj_func(func) {};
   virtual void Call(void *sender)
   {
      (m_target_obj->*(m_target_obj_func))(sender);
   }
};

class TButton
{
private:
   
public:
   TNotifyEvent *OnClick;

   void Click()
   {
      if (OnClick)
      {
         OnClick->Call(this);
      }
   }

   void BtnDoSomething(void) {}
};

class TForm
{
private:
   void FormDoSomething(void) {}
public:
   TButton btn;

   void btn_click(void *sender)
   {
      printf("Button clicked!");
      reinterpret_cast<TButton *>(sender)->BtnDoSomething();
      
      FormDoSomething();
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
   TForm frm;
   
   frm.btn.OnClick = new TTNotifyEvent<TForm>(&frm, &TForm::btn_click);
   
   frm.btn.Click();

   delete frm.btn.OnClick;

   return 0;
}
Angry
Уже с Приветом
Posts: 1491
Joined: 02 Jul 2003 22:47

Post by Angry »

Спасибо, я понял в чем дело - в с++ нет RTTI и по ссылке на объект нельзя узнать что это за класс и какие в нем есть методы.

Интересно, а как это обходится в C++ Builder. Неужели через шаблоны? 8O
uniqueman
Уже с Приветом
Posts: 2013
Joined: 16 Mar 2002 10:01
Location: New York City

Post by uniqueman »

Angry wrote:в с++ нет RTTI


неверно. смотри typeid и так далее
Yuri_p33
Уже с Приветом
Posts: 394
Joined: 12 Feb 2001 10:01
Location: USA

Post by Yuri_p33 »

Angry wrote:Интересно, а как это обходится в C++ Builder. Неужели через шаблоны? 8O
Afaik, Builder использует нестандартное расширение С++. См. keyword "closure", кажется...
Yuri_p33
Уже с Приветом
Posts: 394
Joined: 12 Feb 2001 10:01
Location: USA

Post by Yuri_p33 »

Angry wrote:Спасибо, я понял в чем дело - в с++ нет RTTI и по ссылке на объект нельзя узнать что это за класс и какие в нем есть методы.
Я не вижу, как RTTI тут может помочь. Вам же нужно в compile-time проверять, подходит ли сигнатура обработчика события к определению этого события. А RTTI - это run-time.
Angry
Уже с Приветом
Posts: 1491
Joined: 02 Jul 2003 22:47

Post by Angry »

Yuri_p33 wrote:
Angry wrote:Спасибо, я понял в чем дело - в с++ нет RTTI и по ссылке на объект нельзя узнать что это за класс и какие в нем есть методы.
Я не вижу, как RTTI тут может помочь. Вам же нужно в compile-time проверять, подходит ли сигнатура обработчика события к определению этого события. А RTTI - это run-time.


В делфи можно написать.

var obj:tobject;
but:tbutton;
begin

tbutton(obj)=but;
obj.onclick;

end;

А мне именно это и нужно было. Вообще для моей текущей конкретной задачи можно обойтись и без run-time определения типа, вопрос я задал из чисто теоретических соображений
Yuri_p33
Уже с Приветом
Posts: 394
Joined: 12 Feb 2001 10:01
Location: USA

Post by Yuri_p33 »

Angry wrote: var obj:tobject;
but:tbutton;
begin

tbutton(obj)=but;
obj.onclick;

end;
Imho, этот код не скомпилится. Да и событий тут я не вижу...

Return to “Вопросы и новости IT”