Указатель на функцию как член класса

В чем разница между функцией класса и глобальной функцией в отношении указателей на функции в C ++? Я спрашиваю, поскольку метод Windows CreateThread, похоже, не принимает функцию, в которую входит код потока, если функция является членом класса.

Я могу передать функцию (в которую входит код потока) в сообщение CreateThread, когда это глобальный метод, но как только я сделаю его членом класса, я получаю ошибку «аргумент типа [макет метода] несовместим с параметром типа LPTHREAD_START_ROUTINE «. ClassName :: * теперь находится посередине; это влияет на это?

Как это обойтись?

лямбда-выражения в C ++ 11 или boost :: bind перед этим — опубликуйте ошибочный код, и мы покажем вам, как   —  person Ghost    schedule 14.08.2013

Сигнатура возможных потоковых функций должна быть точно согласована, Win32-API — это чистый C API, не предназначенный для работы с C ++ — классами.   —  person Ghost    schedule 14.08.2013

@doctorlove, результат не будет совместим с указателем на функцию, взятым CreateThread.   —  person Ghost    schedule 14.08.2013

В C ++ 11 вы можете подумать о переходе на стандартную библиотеку потоковой передачи. Тогда это что-то вроде thread([this]{member();}), а не тарабарщина в правильном ответе, с переносимостью в качестве бонуса.   —  person Ghost    schedule 14.08.2013

@MikeSeymour, Хорошая мысль, я не знаю, почему это не пришло мне в голову. Я поставлю это на видное место.   —  person Ghost    schedule 14.08.2013

См. также:  Заводская функция, возвращающая объект определенного типа - как это сделать лучше
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 2
  1. Ghost

    Указатели на функции-члены (DWORD(WINAPI Foo::*)(LPVOID)) отличаются от типов указателей на функции (DWORD(WINAPI *)(LPVOID)). Функции-члены имеют скрытый параметр this, вызывающий несоответствие подписи.

    Самый простой способ сделать это — использовать заголовок <thread> C ++ 11:

    struct Foo {
        void threadProc() {}
    };
    
    int main() {
        Foo foo;
        std::thread t{&Foo::threadProc, foo, /*other arguments to threadProc*/};
        t.join();
    }
    

    Если вам нужно прибегнуть к CreateThread, используйте параметр void * для передачи экземпляра:

    struct Foo {
        DWORD threadProc() {...}
    };
    
    extern "C" DWORD WINAPI proxyThreadProc(LPVOID userData) {
        auto foo = static_cast<Foo *>(userData);
        if (foo) {foo->threadProc();}
    }
    
    int main() {
        Foo foo;
        CreateThread(..., proxyThreadProc, &foo, ...);
    }
    

    Один в вашем классе теперь может быть практически любым, каким вы хотите (например, std::function), и по-прежнему работать, пока он вызывается с правильными аргументами из процедуры прокси.

    Стоит отметить, что это также могло бы работать, если бы proxyThreadProc был статической функцией-членом Foo. Иногда это хороший способ использовать частные функции-члены в таких ситуациях. person Ghost; 14.08.2013

    Разве после функции extern C не должно быть символа «{» и закрывающего символа «}»? person Ghost; 14.08.2013

    @MagnusHoff, для меня это тоже ново, но прочтите это. person Ghost; 14.08.2013

    @Kevin, фигурные скобки нужны только для заключения множественных. person Ghost; 14.08.2013

    @chris О. Спасибо. Соответствующая цитата: обратите внимание, что функция обратного вызова C, реализованная в C ++, должна быть extern "C". Может показаться, что она работает как статическая функция в классе, потому что статические функции класса часто используют то же соглашение о вызовах, что и функция C. Однако это ожидает своего появления ошибка (см. Комментарии ниже), поэтому, пожалуйста, не делайте этого — вместо этого используйте extern "C" оболочку. (Интересное обсуждение темы) person Ghost; 14.08.2013

    @MagnusHoff, Да, и на самом деле, в Windows, я считаю, что вероятность того, что это когда-либо станет проблемой, мала и равна нулю (вероятно, поэтому я так долго не знал об этом), но лучше иметь более правильный код. person Ghost; 14.08.2013

  2. Ghost

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

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: