2013-03-27 2 views
0

Я пытаюсь присоединиться старый кусок кода в C моей нынешней VC++ проекта:ошибка C2664 вследствие Cdecl и MyCLASS конфликт

// .h 
    class DMSinv : public CDialog { 
     double finte(double z); 
     double ITFStolz(double Zp1, double Zp2, double Zc); 
    }; 

// .cpp 
    double Zcglob; 
    double DMSinv::finte(double z) 
    { 
     return TFStolz(z, Zcglob); 
    } 

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc) 
    { 
     int ierr; 
     Zcglob = Zc; 

     return (coteglob(&DMSinv::finte, Zp1, Zp2, 1.0e-10, &ierr)); 
    //error C2664: 'DMSinv::coteglob' : cannot convert parameter 1 from 'double (__thiscall DMSinv::*)(double)' to 'double (__cdecl *)(double)'  

    } 

функция coteglob происходит от старого C части, и finte является промежуточную функцию для передачи функции TFStolz в coteglob.

Я искал на форумах и нашел этот родственный вопрос: How to convert void (__thiscall MyClass::*)(void *) to void (__cdecl *)(void *) pointer , который я пытался применить таким образом:

// .h 
    class DMSinv : public CDialog { 
     virtual double finte(double z); 
     double ITFStolz(double Zp1, double Zp2, double Zc); 
    }; 

// .cpp 
    double Zcglob; 
    extern "C" 
    { 
     static double __cdecl finteHelper(double z) 
     { 
      DMSinv* datainv = reinterpret_cast<DMSinv> (z); //error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'DMSinv' 

      datainv->finte(z); 
     } 
    } 

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc) 
    { 
     int ierr; 
     Zcglob = Zc; 
     double solution = coteglob(&finteHelper, Zp1, Zp2, 1.0e-10, &ierr); 
     return solution; 
    } 

, но до сих пор не работает. Может ли кто-нибудь направить меня на то, как его адаптировать? Я еще совсем новичок, и это кажется далеким от моих знаний.

Заранее благодарен!

+0

'DMSinv * datainv = reinterpret_cast < DMSinv > (z)' - не следует ли использовать команду 'DMSinv *'? – SomeWittyUsername

+0

Я пробовал, но это дает мне ту же ошибку: 'error C2440: 'reinterpret_cast': не может конвертировать из 'double' в 'DMSinv *'' – madoro

ответ

0

Не уверен, что можно сделать как хотите. Единственным вариантом, который приходит мне на ум, является использование некоторой статической переменной для хранения адреса объекта DMSinv. Это ограничивает вас 1 нить с простой реализацией ...

Попробуйте это:

// .h 
class DMSinv : public CDialog { 
    double finte(double z); 
    double ITFStolz(double Zp1, double Zp2, double Zc); 

private: 
    static DMSinv* _current; 
    static double __cdecl finteHelper(double z); 
}; 

// .cpp 
double Zcglob; 
DMSinv* DMSinv::_current = 0; 
double DMSinv::finte(double z) 
{ 
    return TFStolz(z, Zcglob); 
} 

double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc) 
{ 
    int ierr; 
    Zcglob = Zc; 

    _current = this; 
    return (coteglob(DMSinv::finteHelper, Zp1, Zp2, 1.0e-10, &ierr)); 
} 

double __cdecl DMSinv::finteHelper(double z) 
{ 
    return _current->finte(z); 
} 

Это не хорошее решение ИМО, но я не уверен, что есть другой способ.

PS Чтобы удалить предел одного потока вы можете использовать TLS слоты или в VC++ просто __declspec(thread). С последним просто добавьте __declspec(thread) в _current вот так: static __declspec(thread) DMSinv* _current;. НО!!! помните о том, что количество переменных в потоке ограничено для процесса. Подробнее об этом читайте в MSDN.

UPDATE

Юридическая информация: Просто для удовольствия.

Теоретически, есть иная возможность. Вы можете сохранить код сборки в массиве, прикрепленный к объекту. Этот код сборки должен быть функцией __cdecl, которая просто переводит __cdecl в __thiscall на основе регистра eip. Но это никогда не должно выполняться, хотя ...: D

+0

Почему это спрашивает меня о значении в возврате в конечном Helper, нужно ли когда-то статично? 'error C4716: 'DMSinv :: finteHelper': должен возвращать значение'. Спасибо за '__declspec (thread)', выглядит интересно, я посмотрю. – madoro

+0

Я исправляю свой код, чтобы исправить эту ошибку. Просто добавьте return as, компилятор спросит вас. –

+0

ОК, спасибо, теперь он компилируется, но не работает, ломается в какой-то момент. Я буду продолжать исследовать, почему это происходит, поскольку вы сказали, что это может быть не лучшее решение, но спасибо за помощь! – madoro

0

Я не думаю, что вы можете сделать это таким образом. Вам нужно как-то передать ссылку на ваш объект (this). В связанном вопросе параметр функции был определен как тип void *, таким образом, вы могли передать все, что вам нужно для этой функции, включая указатель на this. Ваша функция принимает double, поэтому вы не можете пройти this.

Я думаю, что проще всего определить вашу промежуточную функцию вне класса, так как она не зависит от внутренних элементов класса. Что-то вроде этого:

double finte(double z) 
{ 
    return TFStolz(z, Zcglob); 
} 

Вы также можете хранить указатель на экземпляр в общественном глобальной/статической переменной в классе, что статическая функция может читать.

+0

Это казалось простым и чистым решением, но TFStolz - это функция класс DMSinv, поэтому, если finte вне класса, он не распознает TFStolz: 'ошибка C3861: 'TFStolz': идентификатор не найден'. Может быть, с указателями в finte, чтобы включить TFStolz ... Я должен переосмыслить это, поскольку я сказал, что я новичок, и у меня нет проблем с этими проблемами. Благодаря! – madoro