Указатель на проблему с функциями класса - PullRequest
5 голосов
/ 13 января 2009

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

Сторонняя библиотека имеет функцию "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 в синглтоне? Или мне нужен отдельный класс Hook и, если да, как я могу получить доступ к функциям MyFrameGrabber? Заранее спасибо.

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

Ответы [ 2 ]

7 голосов
/ 13 января 2009

Ваш метод закрытого члена имеет неявный указатель 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() должно быть легко найдено при наличии полной сигнатуры функции, включая имена доступных параметров.

2 голосов
/ 13 января 2009

Причина, по которой «& 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, ...);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...