2013-08-14 5 views
3

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

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

Каково это?

+1

lambdas in C++ 11 или boost :: bind до этого - опубликуйте код нарушения, и мы покажем вам, как – doctorlove

+0

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

+0

@doctorlove, Результат не будет совместим с указателем функции, сделанным 'CreateThread'. – chris

ответ

5

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

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

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), и все еще работать, если он вызывается с правильными аргументами из процедуры прокси.

+1

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

+0

Не следует ли «extern» C «'следовать за« {»и закрытием«} после функции? – Kevin

+0

@MagnusHoff, для меня это тоже ново, но [прочитайте это] (http://stackoverflow.com/questions/1738313/c-using-class-method-as-a-function-pointer-type). – chris

0

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