Добрый день.
Существует библиотека (AntTweakBar), которая позволяет передавать указатель на функцию, которая должна вызываться для получения значения.
Функция имеет следующий typedef:
typedef void (__stdcall * TwGetVarCallback)(void *value, void *clientData);
Внутри своей dll я передаю внутрь этой функции — соответствующую статическую функцию класса:
static void TW_CALL GetData(void* val, void* clientdata);
Все работает, если реализовать функцию следующим образом:
void TW_CALL ATBVar::GetData(void* val, void* clientdata)
{
*static_cast<GLfloat*>(val) = 1.0;
}
Все не работает, если реализовать эту функцию:
void TW_CALL ATBVar::GetData(void* val, void* clientdata)
{
static_cast<ATBVar*>(clientdata)->get(clientdata);
}
В данном случае в clientdata сохранен указатель на производный класс, а функция get является виртуальной функцией базового класса.
Внутри библиотеки вызов функции осуществляется следующим образом:
if( UseGet ){
std::cout << "ValueToDouble() 0.0" << std::endl;
m_GetCallback(&Val, m_ClientData);
std::cout << "ValueToDouble() 0.1" << std::endl;
}
Без вызова виртуальной функции — все работает нормально, т.е. выводятся обе отладочные строки.
С вызовом виртуальной функции — выводится только первая строка и работа AntTweakBar становится абсолютно некорректной.
Я предполагаю, что затирается код возврата из статической функции при вызове виртуальной функции. Если это действительно так, то как быть в этой ситуации? Либо в чем может быть дело?
Планирую сейчас протестировать, что будет, если избавиться от виртуальных функций и вызывать просто функцию класса, может в этом дело.
17.12.13 15:38: Перенесено из 'C/C++'
Ошибка была в:
void TW_CALL ATBVar::GetData(void* val, void* clientdata)
{
static_cast<ATBVar*>(clientdata)->get(clientdata);
}
Из-за невнимательности

Тему можно закрывать.
Здравствуйте, ak239, Вы писали:
A>В данном случае в clientdata сохранен указатель на производный класс, а функция get является виртуальной функцией базового класса.
Несмотря на то, что ошибка найдена и исправлена, — хочу обратить внимание на одну грабельку, которая здесь не сработала, но, в принципе, может сработать.
Дело в возможном смещении баз.
struct A { int x; };
struct B { int y; virtual void f() {} };
struct C { int z; virtual void g() {} };
struct D : A, B, C { int t; };
int main()
{
D d;
D* pd = &d;
C* pc = pd;
std::cout << static_cast <void*>(pd) << std::endl; // 0x22fd50
std::cout << dynamic_cast<void*>(pc) << std::endl; // 0x22fd50 -- отдаёт указатель на первую базу с виртуальными функциями, даже из указателя на другую
std::cout << static_cast <A*> (pd) << std::endl; // 0x22fd5c -- базы A и B переставлены местами
std::cout << static_cast <B*> (pd) << std::endl; // 0x22fd50
std::cout << static_cas t<C*> (pd) << std::endl; // 0x22fd60 -- база C смещена
}
Поэтому
void foo(void* param)
{
C* pc = static_cast<C*>(param);
}
void bar(D* pd)
{
// неправильно (приведение по умолчанию, между прочим!)
foo(pd); // D* -> void* -> C*
// неправильно (всякие рукодельные способы)
foo(static_cast<void*>(pd)); // D* -> void* -> C* (то же, что и неявное)
foo(dynamic_cast<void*>(pd)); // D* -> B* -> void* -> C*
// правильно
foo(static_cast<C*>(pd)); // D* -> C* -> void* -> C*
}
либо, если в искомой базе заведомо есть виртуальные функции,
void foo(void* param)
{
C* pc = dynamic_cast<C*>(param);
}
void bar(D* pd)
{
foo(pd); // D* -> void* -> C*
foo(dynamic_cast<void*>(pd)); // D* -> B* -> void* -> C*
foo(static_cast<C*>(pd)); // D* -> C* -> void* -> C*
}
Здравствуйте, Кодт, Вы писали:
К>Поэтому
я бы еще в качестве правильного варианта предложил такое:
void bar(D* pd)
{
foo(pd); // D* -> void*
}
void foo(void* param)
{
C* c = static_cast<D*>(param); // void* -> D* -> (implicit static_cast) -> C*
}
руководствуясь правилом: делай static_cast из void* только на тот тип, который реально передается (сам придумал, много не бейте)