Указатель функции на проблемы с функциями-членами класса

StackOverflow https://stackoverflow.com/questions/439540

  •  22-07-2019
  •  | 
  •  

Вопрос

Прежде всего, я должен признать, что мои навыки программирования довольно ограничены, и я взял на себя (действительно небольшой) существующий ООП-проект C++, в который пытаюсь внедрить свои собственные разработки.К сожалению, у меня возникла проблема, выходящая за рамки моих знаний, и я надеюсь найти здесь помощь.Я работаю со сторонней библиотекой (которую нельзя изменить) для получения изображений с камеры и буду использовать здесь некоторые имена-заполнители.

Сторонняя библиотека имеет функцию «ThirdPartyGrab» для запуска непрерывного захвата в реальном времени и принимает указатель на функцию, которая будет вызываться каждый раз при поступлении нового кадра.Итак, в обычном приложении C это выглядит так:

ThirdPartyGrab (HookFunction);

«HookFunction» необходимо объявить как:

long _stdcall HookFunction (long, long, void*);

или «BUF_HOOK_FUNCTION_PTR», который объявлен как

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);

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

long _stdcall HookFunction (long, long, void*);

Также в моем классе есть общедоступная функция void «StartGrab», которая должна запустить Grab.Внутри я пытаюсь позвонить:

ThirdPartyGrab (..., HookFunction, ...);

что (неудивительно) терпит неудачу.В нем говорится, что вызов функции MyFrameGrabber::HookFunction пропускает список аргументов, и мне следует вместо этого попытаться использовать &MyFrameGrabber::HookFunction для создания указателя.Однако передача «&MyFrameGrabber::HookFunction» вместо этого приводит к другой ошибке, которую невозможно преобразовать в BUF_HOOK_FUNCTION_PTR.

После прочтения Указатели на функции C++ FAQ Кажется, я понимаю проблему, но не могу найти решение.Я попытался сделать функцию-перехватчик статической, но это также привело к ошибке преобразования.Я также думал о том, чтобы разместить функцию-перехватчик вне класса, но мне нужно использовать функции класса внутри функции-перехватчика.Есть ли другой способ или мне нужно изменить всю концепцию?

РЕДАКТИРОВАТЬ 14.01.08:Я протестировал обходной путь синглтона, поскольку не могу изменить стороннюю библиотеку, а указатель void предназначен только для данных, которые используются внутри функции перехвата.К сожалению, из коробки это не сработало, как я надеялся....Я не знаю, должна ли статическая функция быть в отдельном классе, поэтому я поместил ее в свой класс «MyFrameGrabber»:

static MyFrameGrabber& instance()
{
        static MyFrameGrabber _instance;
        return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file

В моем файле cpp у меня есть функция call_hook:

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
    return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
    ThirdPartyGrab(..., call_hook, ...);
}

Но это дает мне ошибку в static MatroxFrameGrabber _instance; что соответствующий стандартный конструктор не найден.Это правильно, потому что мой конструктор MyFrameGrabber выглядит так:

MyFrameGrabber (void* x,
                const std::string &y, int z,
                std::string &zz);

Я попытался добавить пустой конструктор MyFrameGrabber(); но это приводит к ошибке компоновщика.Должен ли я передавать пустые параметры конструктору MyFrameGrabber в синглтоне?Или мне нужен отдельный класс-перехватчик, и если да, то как я могу получить доступ к функциям MyFrameGrabber?Заранее спасибо.

ВТОРАЯ ПРАВКА 15.01.08:Я применил изменения, и теперь он компилируется и связывается.К сожалению, я пока не могу проверить это во время выполнения, потому что это DLL, и у меня еще нет Debug Caller Exe, и есть другие проблемы во время инициализации и т. д.Я отмечу это сообщение как ответ, потому что уверен, что это правильный способ сделать это.

Это было полезно?

Решение

Причина, по которой "&MyFrameGrabber::HookFunction" не может быть преобразована в BUF_HOOK_FUNCTION_PTR, заключается в том, что, будучи членом класса, он неявно имеет в качестве первого параметра указатель "this", поэтому вы не можете преобразовать функцию-член в функцию, не являющуюся членом:две подписи выглядят одинаково, но на самом деле они разные.

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

class IHookInterface{
public:
    virtual long HookFunction(long, long, void*) = 0;
};
 class HookClass : public IHookInterface{
public:
    virtual long Hook(long, long, void*) {
        // your code here... 
    }
};

// новое определение:ThirdPartyGrab(..., IHookInterface, ...);

РЕДАКТИРОВАТЬ – другое возможное решение, если вы не можете изменить библиотеку:используйте синглтон, а не статическую функцию.

class HookClass{
public:
    static HookClass& instance(){
        static HookClass _instance;
        return _instance;
    }
    long Hook(long, long, void*) {
        // your code here... 
    }
};

long call_hook(long x,long y,void * z){
    return HookClass::instance().Hook(x,y,z);
}

ВТОРОЕ РЕДАКТИРОВАНИЕ:вы можете немного изменить одноэлементный класс с помощью метода инициализации, чтобы вызвать конструктор с соответствующими параметрами, но, возможно, это не более элегантно, чем следующее решение, которое проще:

class HookClass{
public:

    HookClass(string x,string y...){
    }

    long Hook(long, long, void*) {
        // your code here... 
    }
};

static HookClass * hook_instance = 0;

long call_hook(long x,long y,void * z){
    if (0 != hook_instance){
        return hook_instance->Hook(x,y,z);
    }
}

int main(){
    hook_instance = new HookClass("x","y");
    ThirdPartyGrab(..., call_hook, ...);
}

Другие советы

Ваш частный метод-член имеет неявное this указатель в качестве первого аргумента.Если вы это запишете, то станет очевидно, что сигнатуры функций не совпадают.

Вам нужно написать статическую функцию-член, которую можно будет передать в качестве функции обратного вызова в библиотеку.Последний аргумент в пользу HookFunction, а void*, мне очень похоже на файл cookie, куда можно передать собственный указатель.

Итак, в целом должно быть примерно так:

class MyClass {
  long MyCallback(long, long) {
    // implement your callback code here
  }

  static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) {
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b);
  }
public:
  void StartGrab() {
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...);
  }
};

Это, конечно, работает только в том случае, если void* аргумент делает то, что я сказал.Позиция this в ThirdPartyGrab() call должно быть легко найти при наличии полной сигнатуры функции, включая имена доступных параметров.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top