Здравствуйте Нартов Андрей Евгеньевич, вы писали:
НАЕ>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
уточните зачем это надо. А так пиши (GERERIC_FUCTION_TYPE)MyClass.MyStrangeMethod();
A>уточните зачем это надо.
например, сделать нить (CreateThread()) из нестатической member function
А> так пиши (GERERIC_FUCTION_TYPE)MyClass.MyStrangeMethod();
(GENERIC_FUCTION_TYPE) — как я понимаю выглядит так:
DWORD (WINAPI* MyStrangeFunction)( LPVOID )
и компилятор совершенно справедливо говорит на это вот что:
[C++ Error] Unit1.cpp(30): E2031 Cannot cast from 'unsigned long (__stdcall * (_closure )(void *))(void *)' to 'unsigned long (__stdcall *)(void *)'
Но ведь должен быть какой-то способ сделать такое преобразование указателей?
НАЕ>Но ведь должен быть какой-то способ сделать такое преобразование указателей?
Способ конечно есть, только не нужно это...
Вообще, посмотрите тему "Адрес метода" в этом форуме,
там обсуждается разница между статическими и нестатическими функциями.
Здравствуйте Нартов Андрей Евгеньевич, вы писали:
A>>уточните зачем это надо. НАЕ>например, сделать нить (CreateThread()) из нестатической member function
Ну, для этого можно обойтись и вызовом не статической функции из статической или глобальной, а вообще... я как то выпердривался с этим делом. Как сделать это на C++ я не раскопал. На Delpth это делается легко. На Плюсах пришлось выпендриваться с asm-ом.
Общая идея такова — записываем указатель на фунцию и на this экземпляра объекта в структуру.
И эмулируем вызов функции. Вот код:
// Структура для передачи указателя на функцию класса
struct CUniversalFuncPtr
{
void * pF; // Указатель на функцию класса
// Заметьте — это простой указатель на начало области
// кодом занимаемой кодом функции.
void * pThis; // Указатель на this экземпляр класса
};
// Подопытный кролик. :)
class CClass
{
public:
void f1(int i)
{
printf("i = %d, m_i = %d", i, m_i);
}
int m_i;
};
// Функция динамически вызывающаяя функцию любого класса.
// UniversalFuncPtr — унивирсальный указатель :))
// i — параметр передаваемый в вызываемую функцию.
void SomeCaller(CUniversalFuncPtr UniversalFuncPtr, int i)
{
__asm
{
// Эмулируем thiscall
mov ecx, UniversalFuncPtr.pThis;
mov eax, UniversalFuncPtr.pF;
push i ; // закладываем значение параметра
call eax // ecx->f1(i);
}
}
int main(int argc, char* argv[])
{
// Создаем переменную — подопытного кролика...
CClass c1;
// и инициализируем ее переменную-член...
c1.m_i = 123456;
// Поулучаем указатель на функцию некоторого класса.
// Совершенно неважно какой это класс, главное что функция
// должна быть описанна как:
// void FuncName(int);
typedef void ( CClass::*pmfnP)(int);
pmfnP pFunction = &CClass::f1;
CUniversalFuncPtr UniversalFuncPtr;
// Закладываем указатель на объекта (this)
UniversalFuncPtr.pThis = (void*)&c1;
// Закладываем указатель на функцию
__asm { mov eax, dword ptr pFunction }
__asm { mov UniversalFuncPtr.pF, eax }
// Приведенные выше операторы аналогичны конструкции:
// UniversalFuncPtr.pF = (void*)pFunction;
// но к сожалению такая конструкция вызывает сообщение об ошибке:
// error C2440: 'type cast' : cannot convert from
// 'void (__thiscall CClass::*)(int)' to 'void *'
// ...
SomeCaller(UniversalFuncPtr, 55555);
getchar();
return 0;
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Нартов Андрей Евгеньевич, вы писали:
НАЕ>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
В VC++ 6 насколько я помню в функциях-членах this передаётся в регистре EAX, а дальше
идут остальные параметры. Тут нужны будут какие-то извращения с АСМом.
P.S. Зачем всё это надо, наверное ФСБ грохать? :)
Здравствуйте zelyony, вы писали:
Z>Здравствуйте Нартов Андрей Евгеньевич, вы писали:
НАЕ>>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
Z>В VC++ 6 насколько я помню в функциях-членах this передаётся в регистре EAX, а дальше Z>идут остальные параметры. Тут нужны будут какие-то извращения с АСМом. Z>P.S. Зачем всё это надо, наверное ФСБ грохать? :)
ты что-ли ? =)
Здравствуйте Нартов Андрей Евгеньевич, вы писали:
НАЕ>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
Нет. Указатель на функцию и указатель на метод класса — объекты совершенно разной природы в С++ и никакого преобразования между ними быть не может. И даже на уровне бинарного представления в общем случае внутреннее устройство этих указателей может сильно различаться (здесь уже речь идет о конкретных платформах/компиляторах, разумеется).
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Нет. Указатель на функцию и указатель на метод класса — объекты совершенно разной природы в С++ и никакого преобразования между ними быть не может. И даже на уровне бинарного представления в общем случае внутреннее устройство этих указателей может сильно различаться (здесь уже речь идет о конкретных платформах/компиляторах, разумеется).
не правда
точно такой же вызов, только дополнительно ECX = this
Re[4]: Преобразование указателей
От:
Аноним
Дата:
17.03.03 05:28
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте Нартов Андрей Евгеньевич, вы писали:
A>>>уточните зачем это надо. НАЕ>>например, сделать нить (CreateThread()) из нестатической member function
VD>Ну, для этого можно обойтись и вызовом не статической функции из статической или глобальной, а вообще... я как то выпердривался с этим делом. Как сделать это на C++ я не раскопал. На Delpth это делается легко. На Плюсах пришлось выпендриваться с asm-ом.
VD>Общая идея такова — записываем указатель на фунцию и на this экземпляра объекта в структуру. VD>И эмулируем вызов функции. Вот код:
Можно прекрасно обойтись и без asm'а. Идея в целом такая же. Вот пример того, как можно запустить методы в других потоках используя POSIX API (проверялось на Linux, gcc).
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
template<class T>
struct Launcher {
private:
T *m_pThis; // указатель на объект, чей метод будет вызванvoid (T::*m_pMethod)(); // указатель на метод
pthread_mutex_t m_mutex; // дополнительные поля для синхронизации потоков
pthread_cond_t m_condv; // . . .bool volatile m_bReady; // . . .
// системно-зависимая функция с которой начинается выполнение потокаstatic void *threadfunc(void *p) {
// достаем указатели на объект и его метод
Launcher<T> *pObj = (Launcher<T> *) p;
T *pThis = pObj->m_pThis;
void (T::*pMethod)() = pObj->m_pMethod;
// говорим главному потоку, что все нормально
pthread_mutex_lock(&pObj->m_mutex);
pObj->m_bReady = true;
pthread_cond_signal(&pObj->m_condv);
pthread_mutex_unlock(&pObj->m_mutex);
// запускаем метод
(pThis->*pMethod)();
return 0;
}
public:
Launcher(T *pThis, void (T::*pMethod)()): m_pThis(pThis), m_pMethod(pMethod) {
pthread_mutex_init(&m_mutex, 0);
pthread_cond_init(&m_condv, 0);
}
~Launcher() {
pthread_cond_destroy(&m_condv);
pthread_mutex_destroy(&m_mutex);
}
void start() {
pthread_t thr;
m_bReady = false;
// запускаем поток, указываем функцию, с которой поток должен начать работу (threadfunc), и параметр для нее (this)
pthread_create(&thr, 0, threadfunc, this);
// ждем сигнала от запущенного потока, для того, чтобы потом можно было удалить объект Launcher из стека,
// будучи уверенным, что запущенному потоку он уже не нужен.
pthread_mutex_lock(&m_mutex);
if(!m_bReady)
pthread_cond_wait(&m_condv, &m_mutex);
pthread_mutex_unlock(&m_mutex);
}
};
template<class T>
void launch(T *pThis, void (T::*pMethod)()) {
Launcher<T> box(pThis, pMethod);
box.start();
}
// пример использованияstruct A {
void func() {
printf("%s\n", __PRETTY_FUNCTION__);
}
};
struct B {
void func1() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void func2() {
printf("%s\n", __PRETTY_FUNCTION__);
}
};
int main() {
A a;
B b;
launch(&a, &A::func);
launch(&b, &B::func1);
launch(&b, &B::func2);
usleep(1000);
return 0;
}
Тоже самое можно написать, используя Win32 API. Этот код никак не зависит от того, в каких регистрах что находится и как на низком уровне осуществляется вызов методов и функций.
--
Дмитрий
PS В этом примере потоки создаются joinable и им нужно было бы сделать pthread_join, чтобы не оставались потоки-зомби. Но я не стал этого делать чтобы не перегружать пример особенностями поточной библиотеки.
Здравствуйте, Нартов Андрей Евгеньевич, Вы писали:
A>>уточните зачем это надо. НАЕ>например, сделать нить (CreateThread()) из нестатической member function
А>> так пиши (GERERIC_FUCTION_TYPE)MyClass.MyStrangeMethod(); НАЕ>(GENERIC_FUCTION_TYPE) — как я понимаю выглядит так: НАЕ>DWORD (WINAPI* MyStrangeFunction)( LPVOID ) НАЕ>и компилятор совершенно справедливо говорит на это вот что:
Здравствуйте, Нартов Андрей Евгеньевич, Вы писали:
НАЕ>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
Давай забудем на время об указателях...
А вообще есть смысл говорить о методах объекта без самого объекта?
Ну представь, к примеру, класс "Дверь" и метод "Открыть".
А теперь попробуй открыть дверь в твою квартиру не имея самой двери.
Есть в этом смысл? На мой взгляд смысла в этом нем.
С указателями на методы объекта в С++ ситуация абсолютно такая же.
Здравствуйте, Аноним, Вы писали:
АТ>>Нет. Указатель на функцию и указатель на метод класса — объекты совершенно разной природы в С++ и никакого преобразования между ними быть не может. И даже на уровне бинарного представления в общем случае внутреннее устройство этих указателей может сильно различаться (здесь уже речь идет о конкретных платформах/компиляторах, разумеется).
А>не правда А>точно такой же вызов, только дополнительно ECX = this
Неверно.
(Я не понимаю, что происходим с форумом и что здесь делает это замшелое сообщение, но на всякий случай отвечу).
Вызов тебе кажется "точно таким же" потому, что ты еще, скорее всего, мало видел этих вызовов. Советую тебе на досуге подумать над результатами, респечатываемыми вот такой программой
#include <iostream>
#ifdef _MSC_VER
#pragma pointers_to_members(full_generality, multiple_inheritance)
#endif
class A {};
int main()
{
std::cout << sizeof(void (A::*)()) << std::endl;
std::cout << sizeof(void (*)()) << std::endl;
}
Здравствуйте, zelyony, Вы писали:
Z>Здравствуйте Нартов Андрей Евгеньевич, вы писали:
НАЕ>>Преобразовать указатель на функцию — метод объекта (не статическую) в указатель на обычную функцию. Возможно ли это?
Z>В VC++ 6 насколько я помню в функциях-членах this передаётся в регистре EAX, а дальше
Здравствуйте, Андрей, Вы писали:
АТ> (Я не понимаю, что происходим с форумом и что здесь делает это замшелое АТ> сообщение, но на всякий случай отвечу).
Это кто-то, читая старые сообщения, решил на них поотвечать. При этом соответствующая
ветка автоматически "всплывает" наверх. Как я понимаю, тебе придется объяснять все заново.
Эдакое "назад в будущее-2"
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
shura_mam wrote:
Z>> В VC++ 6 насколько я помню в функциях-членах this передаётся в регистре EAX, а дальше
sm> На моем VC 6 this всегда передается в ECX.
Здравствуйте, Павел Кузнецов, Вы писали:
АТ>> (Я не понимаю, что происходим с форумом и что здесь делает это замшелое АТ>> сообщение, но на всякий случай отвечу).
ПК>Это кто-то, читая старые сообщения, решил на них поотвечать. При этом соответствующая ПК>ветка автоматически "всплывает" наверх. Как я понимаю, тебе придется объяснять все заново. ПК>Эдакое "назад в будущее-2"
Да, но похоже что дело не в этом. У меня со вчерашнего вечера до сегодняшенго утра форум показывал только какие-то совершенно старинные сообщения. Я понимаю, что старые ветки всплывают наверх, если в них что-то написать, но внимательное изучение верхних веток показало, что ни одного свежего сообщения в них нет. Я так и не понял, что происходило: то ли база сообщений временно "обрубилась" где-то в районе 2001 года и все новые сообщения временно пропали, то ли просто что-то нехорошее произошло с сортировкой и 2001 год почему-то всплыл наверх. К позднему утру все вдруг неожиданно стало на свои места.
Здравствуйте, Андрей, Вы писали:
АТ> Да, но похоже что дело не в этом. У меня со вчерашнего вечера до сегодняшенго АТ> утра форум показывал только какие-то совершенно старинные сообщения.
А... Это другое дело. Я, просто, через web почти сайт не смотрю. Похоже, действительно,
была какая-то ошибка с сортировкой. Во всяком случае во внутрикомандном форуме что-то
такое упоминалось.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
АТ>> Да, но похоже что дело не в этом. У меня со вчерашнего вечера до сегодняшенго АТ>> утра форум показывал только какие-то совершенно старинные сообщения.
ПК>А... Это другое дело. Я, просто, через web почти сайт не смотрю. Похоже, действительно, ПК>была какая-то ошибка с сортировкой. Во всяком случае во внутрикомандном форуме что-то ПК>такое упоминалось.
К сожалению, ошибка еще есть, но теперь в другую сторону
Это сообщение не всплыло вверх, хотя на него последнее ответили.