Russian Qt Forum

Программирование => С/C++ => Тема начата: m_ax от Апрель 21, 2009, 22:16



Название: Об указателях на функции класса
Отправлено: m_ax от Апрель 21, 2009, 22:16
Всем привет!

Предположим у меня есть некоторая функция, аргументом которой является указатель на функцию:

Код
C++ (Qt)
typedef int (*pFunc)(int);
int myFunction(pFunc pf){...}
...
 

Далее, мне захотелось написать некоторый класс, например такой:

Код
C++ (Qt)
class MyClass
{
public:
int function(int x) {return x;} // for example
};
 
   

А теперь, как мне передать в функцию myFunction(pFunc pf) указатель на функцию данного класса (function(int)) ?

ну первое что приходит на ум это примерно так:
Код
C++ (Qt)
#include <iostream>
using namespace std;
 
typedef int (*pFunc)(int);
 
class SomeClass
{
public:
int f(pFunc pf) {return (*pf)(2);} // for example
};
 
class MyClass
{
public:
int function(int x) {return x;} // for example
};
 
int main()
{
SomeClass sc;
int x = sc.f(reinterpret_cast<pFunc>(&MyClass::function));
 
cout << x << endl;
return 0;
}
 

Но компилятор выдаёт ошибку:
Код:
ошибка: преобразование из ‘int (MyClass::*)(int)’ в ‘int (*)(int)’

Есть ли выход, господа?  ???




Название: Re: Об указателях на функции класса
Отправлено: Rcus от Апрель 21, 2009, 22:25
Если не менять сигнатуру, то boost::bind?


Название: Re: Об указателях на функции класса
Отправлено: m_ax от Апрель 21, 2009, 23:09
Спасибо! Пойду раскуривать boost::bind  :)

P.S. Я конечно уважаю библиотеку Boost, но всё же: есть ли ещё решения ?


Название: Re: Об указателях на функции класса
Отправлено: Barmaglodd от Апрель 22, 2009, 07:22
Сделать абстрактный класс
Код:
class IBase
{
public:
        virtual ~IBase() {}
virtual int function(int x)=0;
};
и спользовать его вместо указателя на функцию, иначе boost::bind и boost::function.


Название: Re: Об указателях на функции класса
Отправлено: Rcus от Апрель 22, 2009, 07:39
Ну я же сказал что если не менять сигнатуру функции, иначе можно просто
Код:
typedef ReturnType (ClassName::*MethodPtrType)(ParamType1, ParamType2);


Название: Re: Об указателях на функции класса
Отправлено: Barmaglodd от Апрель 22, 2009, 10:22
Сигнатуру какой функции? Boost::bind или Boost::function умеют приводиться к указателю на функцию? Без изменения int myFunction(pFunc pf){...} разве можно что-то сделать?


Название: Re: Об указателях на функции класса
Отправлено: Tonal от Апрель 22, 2009, 10:23
Если не менять сигнатуру, то только через статическую функцию и запомненный экземпляр.
Никакой boost::bind тут не поможет, т. к. он отдаёт функтор а не указатель на функцию.
Если же сигнатуру можно менять, то вариантов куча. :)


Название: Re: Об указателях на функции класса
Отправлено: m_ax от Апрель 22, 2009, 20:09
Всем спасибо за обсуждение  :)

Ясно что указатели на члены классов ссылаются на область памяти внутри класса, а члены класса определяются смещением. Реальный адрес получается в результате применения смещения к начальному адресу конкретного объекта...
Мне лично хотелось узнать есть ли возможность приведения типа:
Код
C++ (Qt)
pFunc pf = (pFunc)&MyClass::function;
 
 
Ну похоже, что нет... Может это и правильно  :)

Ладно, пойду пивка попью  ;D Ещё раз всем спасибо! 


Название: Re: Об указателях на функции класса
Отправлено: Alex03 от Апрель 23, 2009, 08:07
Всем спасибо за обсуждение  :)

Ясно что указатели на члены классов ссылаются на область памяти внутри класса, а члены класса определяются смещением. Реальный адрес получается в результате применения смещения к начальному адресу конкретного объекта...
Мне лично хотелось узнать есть ли возможность приведения типа:
Код
C++ (Qt)
pFunc pf = (pFunc)&MyClass::function;
 
В каждый не статический метод класса неявно передаётся ещё один параметр - указатель на объект данного класса (тот самый this).

shapoclak Вы лучше расскажите что вам надо в результате, а народ подскажет как красивее это сделать.


Название: Re: Об указателях на функции класса
Отправлено: vaprele07 от Апрель 23, 2009, 10:38
другое дело как этот "this" представляют компиляторы с разной оптимизацией и т.д.
короче так делать не хорошо. проще как выше сказали сделать наследование от IBase какая разница что хранить указатель на функцию или указатель на класс если все равно придется про "this" думать!


Название: Re: Об указателях на функции класса
Отправлено: Eugene Efremov от Апрель 26, 2009, 22:37
Мне лично хотелось узнать есть ли возможность приведения типа:
Код
C++ (Qt)
pFunc pf = (pFunc)&MyClass::function;
 
 
Ну похоже, что нет... Может это и правильно  :)

Даже если бы и была — в результате получился не pFunc, а что-то вроде int (*)(const MyClass*, int). Но на деле — указатели на члены очень сильно отличаются по своему устройству от обычных. Так что никакое подобное приведение невозможно. В принципе, возможно это обойти, но в любом случае — чтобы получить требуемый int (*)(int) придется где-то хранить указатель на объект. С учетом этого получаем примерно такой код:

Код
C++ (Qt)
template<class type, int (type::*fun)(int)>
class StFunc
{
static type *owner;
static int call(int i)
{
return (owner->*fun)(i);
}
public:
static pFunc get_ptr(type *t)
{
owner=t;
return &StFunc<type, fun>::call;
}
};
 
template<class type, int (type::*fun)(int)> type* StFunc<type, fun>::owner;
 

Юзать это дело так:

Код
C++ (Qt)
MyClass m;
pFunc pm = StFunc<MyClass, &MyClass::function>::get_ptr(&m);
 

Главная проблема в том, что и ф-ция call — указатель на которую мы передаем вместо требуемого — должна быть статической (чтобы это был обычный указатель на ф-цию). А значит — указатель на объект MyClass, который она использует, тоже должен быть статическим.
Это в свою очередь означает, что одновременно мы сможем использовать только один такой указатель для каждой пары класс/метод.

Иными словами — это костыль. Очень кривой и с большим количеством потенциальных граблей. Так что единственный случай, когда такое нужно использовать — это если мы не можем никак изменить ф-цию, которая этот самый pFunc хочет. Если же мы ее можем изменить, можно сделать гораздо проще:

Было:
Код
C++ (Qt)
typedef int (*pFunc)(int);
 
int myFunction(pFunc pf)
{
int i;
// do something...
return pf(i);
}
 

Стало:
Код
C++ (Qt)
template<class TFunc>
int myFunction(TFunc pf)
{
int i;
// do something...
return pf(i);
}
 

И все. Теперь мы можем передавать туда не только указатели на ф-ции, но и вообще все, что позволяет применить к нему operator().

Правда, напрямую мы передавать туда указатели на члены все еще не можем: для их вызова все еще требуется указатель на сам объект. А значит — если мы не хотим писать версию myFunction с двумя аргументами — нам все еще нужен переходник. Но теперь он будет устроен гораздо проще, а главное — мы избавились от статики, а значит и от ограничений на одновременное использование:
Код
C++ (Qt)
template<class type>
class MemFun
{
type *owner;
int (type::*fun)(int);
public:
MemFun(type *t, int (type::*f)(int)) : owner(t), fun(f) {}
 
int operator()(int i)
{
return (owner->*fun)(i);
}
};
 
............
// using:
 
MyClass m;
MemFun<MyClass> pm(&m, &MyClass::function);
myFunction(pm);
 

А теперь можно вспомнить, что подобный функционал (причем гораздо более гибкий, чем наш самопальный MemFun) давно уже реализован во всяких Boost и иже с ними. Собственно, именно его и предлагали использовать выше по треду...


Название: Re: Об указателях на функции класса
Отправлено: m_ax от Апрель 27, 2009, 18:00
Eugene Efremov,
Спасибо за исчерпывающий обзор!

По поводу красоты  :)
Цитировать
shapoclak Вы лучше расскажите что вам надо в результате, а народ подскажет как красивее это сделать.

На самом деле на функцию которая получает указатель не накладывается такого жёсткого ограничения, поэтому вариантов здесь не мало, более того, заранее известно даже то, что использовать она будет функцию известного класса и даже известно какую  :) Поэтому самый простой вариант это такой:
Код
C++ (Qt)
int myFunction(MyClass *myClass)
{
   int i;
   ...
   return myClass->function(i);
}
 

Но пересмотрев архитектуру программы, наверно самое логичное решение унаследоваться от абстрактного класса, как предложил Barmaglodd ну и кое что ещё по мелочи изменить...