Привести указатель на функцию-член к обычному указателю - PullRequest
3 голосов
/ 18 ноября 2010

В настоящее время у меня есть класс такого вида, сокращенный для простоты:

class MyClass {
    public: 
        MyClass();
        void* someFunc(void* param);
}

Теперь мне нужно вызвать функцию такого типа (не принадлежащую ни к какому классу и которую я, к сожалению, не могу изменить ), но которую мне все равно нужно вызвать:

void secondFunc(int a, int b, void *(*pCallback)(void*));

Теперь мне нужно передать адрес someFunc экземпляра.

Неработающий образец:

MyClass demoInstance;
// some other calls
secondFunc( 1, 2, demoInstance::someFunc() );

Я пробовал также с приведениями типа:

(void* (*)(void*)) demoInstance::someFunc;
reinterpret_cast<(void* (*)(void*))>(demoInstance::someFunc);

Как я могу вызвать эту функцию с функцией-членом класса в качестве параметра, чтобы эта могла использовать ее в качестве обратного вызова?

Любая идея или замечание приветствуется. Спасибо и всего наилучшего Tobias

Ответы [ 6 ]

8 голосов
/ 18 ноября 2010

Вы не можете вызвать функцию-член напрямую. Указатели на функции-члены не относятся к указателям на функции.

Вам нужно каким-то образом обернуть его в совместимую функцию.Однако, если ваша внешняя функция (та, которая принимает указатель функции в качестве аргумента) не является повторно входящей и не предоставляет дополнительный аргумент для использования указателем функции, вы не сможете передать экземпляр, на который членФункция работает, поэтому вы не сможете совершить звонок.

5 голосов
/ 18 ноября 2010

Разница между функцией C и функцией-членом C ++ заключается в том, что функция C использует cdecl соглашение о вызовах, в то время как функции-члены используют thiscall соглашение о вызовах (и вы даже не можете принятьих адрес!).

Как я понимаю, вы действительно хотите, чтобы secondFunc() вызывал функцию-член определенного экземпляра класса (давайте назовем его this).Ну, адреса функций-членов всех экземпляров определенного класса одинаковы.Чтобы передать указатель на объект, вам понадобится боковой канал.В этом случае это может быть статическая переменная.Или, если вам нужна поддержка MT, вам придется использовать Thread Local Storage (TLS),

Для этого требуется один обратный вызов на элемент SomeFunc, но в любом случае вам понадобится диспетчер.

1 голос
/ 18 ноября 2010

Существует раунд о том, как это сделать. Поскольку имена C ++ искажены, вы не можете напрямую использовать их для нестатических функций. Однако, поскольку нестатические функции имеют те же сигнатуры, что и функции C, вы можете напрямую использовать их в качестве обратных вызовов. Так что для нестатических функций у вас могут быть обертки статических функций. Эта страница подробно объясняет этот подход.

0 голосов
/ 18 ноября 2010

См. Этот образец:

#include <iostream>

class MyClass 
{
public: 
    MyClass()
    {
    }

    void* someFunc(void* param)
    {
        std::cout << "someFunc" << std::endl;
        return (void*)0;
    }
};

typedef void* (MyClass::*MemFun)(void*);

void secondFunc(int a, int b, MemFun fn)
{
    MyClass* ptr = 0;
    // This is dangerous! If the function someFunc do not operate the data in the class.
    // You can do this.
    (ptr->*fn)(0);
    std::cout << "Call me successfully!" << std::endl;
}

int main()
{
    secondFunc(1, 2, &MyClass::someFunc);

    system("pause");

    return 0;
}
0 голосов
/ 18 ноября 2010

Не видел части о невозможности изменить вторую функцию раньше.

Определить структуру с указателями на функцию-член и на объект:

struct MyData {
   MyStruct  *myInstance;
   (void *)(MyStruct::myFunction)(void *data);
   void * dataPointer ;
}

Создатьфункция, которая может вызвать правильный метод:

void *proxyFunc( MyData *data)
{
  return (data->myInstance->*(data->myFunction))(data->dataPointer);
}

Затем вызвать функцию 2 как:

MyData  dataP = { someInstance, &MyStruct::someFunc, &dataPtr };
secondFunc(proxyFunc, &dataP);
0 голосов
/ 18 ноября 2010
class MyClass 
{
public: 
    MyClass();
    void* someFunc(void* param);
};

void* callback(void*)
{
    MyClass instance;
    instance.someFunc(0 /* or whatever */);
}

void foo()
{
    secondFunc( 1, 2, callback);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...