Форум программистов, компьютерный форум CyberForum.ru

Передача указателя функции класса A в класс B - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.70
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
24.08.2010, 17:07     Передача указателя функции класса A в класс B #1
Добрый день!

Стоит задача вызывать функцию другого класса в потоке, ну что то типа этого:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
typedef void (t1::*PTR_FUN)(int); //указатель на не статическую
class t1
{
private:
    void MyFun(int i)
    {
       i++;
    }
};
class t2
{
private:
  // где храниться указатель на функцию  
  PTR_FUN pFun; 
  // функция потока
  static MyThead(LPVOID lpParameter)
  {
     int x = 1000;
     t2* pThis = static_cast<t2*>(lpParameter);
     (pThis->pFun)(x);
  }
public:
  // функция которая принимает указатель на фун. другого класса
  void SetCallBack(PTR_FUN pfun)
  {
     pFun = pfun;
  }
};
а что если в конструкции типа typedef void (t1::*PTR_FUN)(int) имя класса t1 не известно, как быть?????. Проблема в том что нечто подобное класса t2, со всеми заморочками (а именно работа с RS232) я должен отдать заказчику, где он будет подключать его в разные проекты, какие имена классам он даст с которых будет вызываться его функция, меня не должно интересовать, класс должен быть универсальным. Это надо реализовать на MFC
До этого программировал в C++/CLI и С# там просто пишешь delegate и event, цепляй что хочешь, а тут фиг.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.08.2010, 17:07     Передача указателя функции класса A в класс B
Посмотрите здесь:

C++ Передача параметров функции с пoмощью указателя
Передача указателя на функцию-член класса C++
передача указателя на строку методу класса C++
Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... C++
Как при помощи указателя на базовый класс обратится к полю наследуемого класса? C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
rrrFer
Заблокирован
24.08.2010, 19:56     Передача указателя функции класса A в класс B #2
наверно надо использовать абстрактную фабрику
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,896
Завершенные тесты: 1
24.08.2010, 21:11     Передача указателя функции класса A в класс B #3
Ну по идее это задача для функторов.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class AbstractFunctor {   // Прототип для вызывалок. Наследуем от него реальные вызывалки.
public:
    virtual void operator () (int) = 0;    // Оператор для вызова
    virtual ~AbstractFunctor() {}
};
 
// Создадим функтор для вызова метода объекта произвольного типа. 
// Разумеется, в его составе должен быть метод с требуемой сигнатурой.
// Нам понадобится и ссылка на сам объект.
template <typename T>
class MethodFunctor: public AbstractFunctor {
public:
    MethodFunctor(T& Host, void (T::*Fun)(int)): host(Host), fun(Fun) {}
    virtual void operator () (int arg) {host.*fun(arg);}
private:
    T& host;
    void (T::*fun)(int);
};
 
// Так библиотечная часть будет использовать функторы 
// (исключительно через интерфейс AbstractFunctor)
void Receiver::Foo(AbstractFunctor &callback)
{
    callback(7);
}
 
// Так пользовательский код будет обращаться к библиотечному,
// передавая ему функтор, вызывающий void MyClass::MyMethod(int)
void bar(Receiver &rcv)
{
    MyClass mcl;
    rcv.Foo(MethodFunctor<MyClass>(mcl, &MyClass::MyMethod));
}
Вот где-то такая фигня, товарищи. Такой подход, конечно, годится при постоянном и небольшом наборе сигнатур вызова. При большем разнообразии надо уже похитрее колдовать с шаблонами, там всё упрётся в основном в количество аргументов.
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
25.08.2010, 12:27  [ТС]     Передача указателя функции класса A в класс B #4
Спасибо за советы заработало !!! отдельное спасибо Nick Alte функторы это вещь!!!!
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
26.08.2010, 15:44  [ТС]     Передача указателя функции класса A в класс B #5
C++
1
2
3
4
5
6
// Так библиотечная часть будет использовать функторы 
// (исключительно через интерфейс AbstractFunctor)
void Receiver::Foo(AbstractFunctor &callback)
{
    callback(7);
}
с локальным функтором callback понятно, работает, а как быть, если этот Функтор, мне нужно сделать членом класса, чтобы можно было вызывать пользовательскую функцию по нему, например из потока или из другой функции. Объявить AbstractFunctor &callback как член класса нельзя, будет ругаться, что ссылка не инициализирована.
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,896
Завершенные тесты: 1
26.08.2010, 20:07     Передача указателя функции класса A в класс B #6
Если функтор имеется на момент создания твоего объекта и не будет заменяться за всё время жизни объекта, и будет всё это время существовать, инициализируй ссылку в списке инициализации конструктора:
C++
1
2
3
4
5
6
class Ref {
public:
    Ref(SomeType &R): r(R) {}
private:
    SomeType &r;
};
Ну а в более общем случае - пользуйся не ссылками, а указателями на AbstractFunctor, делов-то на рыбью ногу.
rrrFer
Заблокирован
26.08.2010, 20:17     Передача указателя функции класса A в класс B #7
Цитата Сообщение от rrrFer Посмотреть сообщение
наверно надо использовать абстрактную фабрику
присмотрелся к вопросу, фабрика никак не поможет( я ошибся)
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
27.08.2010, 12:34  [ТС]     Передача указателя функции класса A в класс B #8
rrrFer, все равно спасибо что откликнулся, Nick Alte большая тебе уважуха все работает, что то я совсем после C# расслабился, буду исправлять ситуацию
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
02.09.2010, 12:22  [ТС]     Передача указателя функции класса A в класс B #9
Братцы помогите!!!!

не получается вызвать функцию по указателю из потока, вроде все сделал как советовали, если вызывать функцию из моего метода куда я предаю указатель, то все работает, но как только дело дошло до потока, меня ждал облом, при попытке вызова, вылетает программа, ругается, что __vfptr равен нулю. Вот урезанный код того, что я делаю:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Прототип для вызывалок. Наследуем от него реальные вызывалки.
class AbstractFunctor 
{
public: 
    // Оператор для вызова
    virtual void operator () (unsigned char* ptr, int arg){ptr = NULL; arg = 0;}
    virtual ~AbstractFunctor() {}
};
 
 
// Создадим функтор для вызова метода объекта произвольного типа. 
// Разумеется, в его составе должен быть метод с требуемой сигнатурой.
// Нам понадобится и ссылка на сам объект.
template <typename T>
class MethodFunctor: public AbstractFunctor
{
public:
  MethodFunctor(T& Host, void (T::*Fun)(unsigned char*, int)): host(Host), fun(Fun) {}
    virtual void operator () (unsigned char* ptr, int arg) {(host.*fun)(ptr, arg);}
private:
    T& host;
    void (T::*fun)(unsigned char*, int);
};
 
// класс работы с портом
class ComPort
{
private:
  // приемный буфер
  unsigned char m_Buffer[256];
 
  // указатель вызова по приёму данных
  AbstractFunctor *m_CallbackRx;
 
  // функция потока приёма данных
  static MyThead(LPVOID lpParameter)
  {
     int  RxCounter = 0;
     ComPort* pThis = static_cast<ComPort*>(lpParameter);
 
     // какой-то код......
     // принимаем данные 
 
     // вызываем callback функцию
     if (pThis->m_CallbackRx != NULL)
     {
       // передаем указатель на буфер и сколько приняли байт
       // вот здесь меня жал облом
       pThis->m_CallbackRx->operator ()(m_Buffer, RxCounter);
     }
  }
public:
  // прикрепить callback-функцию вызова по приходу данных в буфер
  void SetCallbackRx(AbstractFunctor *callback)
  {
    m_CallbackRx = callback;
    // здесь я проверял что вызов работает
    // m_CallbackRx->operator ()(NULL, 1000);
  }
  
  // открыть порт
  void Open()
  { 
    // код
  }
};
 
// настройка порта и обработка данных
class TestPort
{
   // открытие порта
   void Open()
   {
      comPort.SetCallbackRx(&MethodFunctor<TestPort>(*this, &TestPort::MyMethod));
      comPort.Open();
   }
   // обработка данных
   void CComPortView::MyMethod(unsigned char* ptr, int count)
  {
  }
};
а вот что я вижу в дебаге:
Миниатюры
Передача указателя функции класса A в класс B  
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,896
Завершенные тесты: 1
02.09.2010, 19:03     Передача указателя функции класса A в класс B #10
C++
1
      comPort.SetCallbackRx(&MethodFunctor<TestPort>(*this, &TestPort::MyMethod));
Созданный в этом вызове объект MethodFunctor уничтожается незамедлительно после вызова SetCallbackRx, это ведь временный объект. Для корректной работы надо следить, чтобы функтор существовал в то время, когда происходит вызов callback'а.

Добавлено через 2 минуты
Более того, в том виде, как у тебя это описано, имеет смысл вообще передавать владение функтором классу ComPort:
C++
1
      comPort.SetCallbackRx(new MethodFunctor<TestPort>(*this, &TestPort::MyMethod));
Ну и в самом SetCallbackRx, а также в деструкторе ComPort тогда надо предусмотреть уничтожение старого функтора по delete.
CyBOSSeR
Эксперт C++
 Аватар для CyBOSSeR
2293 / 1663 / 86
Регистрация: 06.03.2009
Сообщений: 3,675
02.09.2010, 21:27     Передача указателя функции класса A в класс B #11
Вариант решения с помощью boost::function, boost::bind:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <windows.h>
#include <process.h>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
 
struct Foo {
  int Bar(int arg) {
    return arg * arg;
  }
};
 
void thread_function(void* p) {
  boost::function<int (int)> functor = *static_cast<boost::function<int (int)>*>(p);
 
  std::cout << functor(100) << std::endl;
}
 
int main() {
  boost::function<int (int)> functor = boost::bind(&Foo::Bar, Foo(), _1);
 
  HANDLE hThread2 = reinterpret_cast<HANDLE>(_beginthread(thread_function, 0, &functor));
  ::WaitForSingleObject(hThread2, INFINITE);
 
  return 0;
}
Пример будет работать аналогично, если thread_function будет статической функцией любого класса.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.09.2010, 11:00     Передача указателя функции класса A в класс B
Еще ссылки по теме:

Передача указателя в качестве параметра функции динамически подключаемой библиотеки .so C++
C++ Передача указателя в класс на объект другого класса
Как происходит передача указателя в/из функции C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
djoni-kga
4 / 4 / 0
Регистрация: 11.11.2008
Сообщений: 66
03.09.2010, 11:00  [ТС]     Передача указателя функции класса A в класс B #12
Nick Alte, как всегда большая уважуха работает!!!! на счет boost::function, boost::bind очень интересный вариант, жаль раньше мне на глаза не попадалось, спасибо буду тестить.
Yandex
Объявления
03.09.2010, 11:00     Передача указателя функции класса A в класс B
Ответ Создать тему
Опции темы

Текущее время: 01:55. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru