Задача 1:
Хотя это может выглядеть и работать на вашей установке, это не гарантированно работает, так как C ++ ABI не определен. Таким образом, технически вы не можете использовать статические функции-члены C ++ в качестве указателей на функции, которые будут использоваться кодом C.
Задача 2:
Все вызовы C (которые я знаю) позволяют вам передавать пользовательские данные обратно как пустоту *. Вы можете использовать это как указатель на ваш объект, который имеет виртуальный метод. НО Необходимо убедиться, что вы используете dynamic_cast <> () для базового класса (класса с виртуальным методом, использованным в обратном вызове), прежде чем он будет преобразован в пустоту *, иначе указатель на другом конце может не может быть правильно истолковано (особенно если задействовано множественное наследование).
Задача 3:
Исключения: C не предназначен для работы с исключениями (особенно старыми библиотеками C с обратными вызовами). Поэтому не ожидайте, что исключения, которые избегают вашего обратного вызова, предоставят звонящему что-то значимое (они с большей вероятностью приведут к завершению приложения).
Решение:
Что вам нужно сделать, так это использовать функцию extern "C" в качестве обратного вызова, который вызывает виртуальный метод для объекта известного типа и отбрасывает все исключения.
Пример для подпрограмм C pthread
#include <iostream>
extern "C" void* start_thread(void* data);
class Work
{
public:
virtual ~Work() {}
virtual void doWork() = 0;
};
/*
* To be used as a callback for C code this MUST be declared as
* with extern "C" linkage to make sure the calling code can
* correctly call it
*/
void* start_thread(void* data)
{
/*
* Use reinterpret_cast<>() because the only thing you know
* that you can do is cast back to a Work* pointer.
*
*/
Work* work = reinterpret_cast<Work*>(data);
try
{
work->doWork();
}
catch(...)
{
// Never let an exception escape a callback.
// As you are being called back from C code this would probably result
// in program termination as the C ABI does not know how to cope with
// exceptions and thus would not be able to unwind the call stack.
//
// An exception is if the C code had been built with a C++ compiler
// But if like pthread this is an existing C lib you are unlikely to get
// the results you expect.
}
return NULL;
}
class PrintWork: public Work
{
public:
virtual void doWork()
{
std::cout << "Hi \n";
}
};
int main()
{
pthread_t thread;
PrintWork printer;
/*
* Use dynamic_cast<>() here because you must make sure that
* the underlying routine receives a Work* pointer
*
* As it is working with a void* there is no way for the compiler
* to do this intrinsically so you must do it manually at this end
*/
int check = pthread_create(&thread,NULL,start_thread,dynamic_cast<Work*>(&printer));
if (check == 0)
{
void* result;
pthread_join(thread,&result);
}
}