Преобразование сигнатур методов

typedef недействительным (__thiscall* LPVOIDPROC) (недействительным);

class ClassA
{
  LPVOIDPROC m_pProc;

  void SetProc(LPVOIDPROC pProc)  { m_pProc = pProc; }

  void OnSomeEvent() { m_pProc(); }
}

class ClassB
{
  ClassA* pCA;

  void Proc() { /* ... */ }

  void Init()
  {
    // Assume pCA != NULL
    pCA->Set((LPVOIDPROC)&ClassB::Proc); // error C2440
  }
}

Как избавиться от этой ошибки C2440: «приведение типа»: невозможно преобразовать из «void (__thiscall ClassB::*) (void)» в «LPVOIDPROC»? Я не хочу ограничивать подпись LPVOIDPROC только классом B. Это должен быть любой класс, и указанный процесс не должен быть статическим.


person Aoi Karasu    schedule 18.02.2010    source источник
comment
Если метод не статичен, как вы передаете экземпляр класса в ClassA?   -  person mmmmmm    schedule 18.02.2010


Ответы (5)


Обходной путь:

typedef void (* CLASSPROC) (void *); 

template<class T, void (T::*proc)()>
void class_proc(void * ptr) 
{
 (static_cast<T*>(ptr)->*proc)();
}

class ClassA 
{ 
 CLASSPROC m_pProc;
 void    * m_pInstance;

public:
 void SetProc(void *pInstance, CLASSPROC pProc)  { 
          m_pInstance = pInstance; 
          m_pProc = pProc; 
     } 

 void OnSomeEvent() { m_pProc(m_pInstance); } 
};

class ClassB 
{ 
 ClassA* pCA; 

 void Proc() { /* ... */ } 

 void Init() 
 { 
  // Assume pCA != NULL 
  pCA->SetProc(this, class_proc<ClassB, &ClassB::Proc>);      
 } 
};
person Alexey Malistov    schedule 18.02.2010

Я отсылаю вас к этой ссылке . Ваш тип LPVOIDPROC — это указатель на функцию, а это не то же самое, что указатель на функцию-член. Когда вы пытаетесь привести ClassB::Proc, вы пытаетесь преобразовать указатель на функцию-член, что является недопустимой операцией.

Вы должны взглянуть на boost::function, который предлагает именно то, что вы ищете. Или вы можете использовать функторы для инкапсуляции ваших функций, если вы не хотите прибегать к повышению. Пример:

struct VoidProcFunctor {
    virtual void call() = 0;
};

class ClassB;
struct BProcFunctor : VoidProcFunctor {
    BProcFunctor(ClassB* b) : b_(b) {}
    void call();
private:
    ClassB* b_;        
}

class ClassA
{
public:
    VoidProcFunctor* m_pProc;

    void SetProc(VoidProcFunctor* pProc)  { m_pProc = pProc; }

    void OnSomeEvent() { m_pProc->call(); }
};

class ClassB
{
    ClassA* pCA;

    void Proc() { /* ... */ }

    void Init()
    {
        // Assume pCA != NULL
        // warning! this is not the best design possible
        BProcFunctor* bproc = new BProcFunctor(this);
        pCA->SetProc(bproc);
    }
};

void BProcFunctor::call() { b_->proc() }
person fogo    schedule 18.02.2010

Нестатические методы требуют указателя this, без указателя this вы не можете его вызвать, поэтому нет смысла приводить его к указателю функции C.

Рассмотрите возможность создания простого класса (назовем его X), который имеет

  • член данных, который ссылается на экземпляр ClassB
  • оператор (хотя я предпочитаю методы с понятными именами), вызывающий ClassB::Proc с использованием экземпляра ClassB в качестве указателя на this.

Вместо того, чтобы передавать указатель на функцию в класс A, создайте экземпляр X (с заполненным его элементом данных в ClassB) и передайте его в класс A. Вместо вызова указателя на функцию класс A должен вызывать x().

Класс X можно даже написать с использованием шаблонов, поэтому, если у вас есть такая ситуация для более чем одного класса, вы должны написать ее только один раз.

Я думаю, что в C# это можно сделать чище с помощью делегатов, но я оставляю это специалистам по C# и .Net.

person Patrick    schedule 18.02.2010

  1. Никогда не выполняйте приведение указателей на функции. Вы можете получить повреждение стека. Не делай этого.

  2. Не передавайте указатели на нестатические функции-члены. Они используют другое соглашение о вызовах и несовместимы.

  3. В вашем случае статичность "Proc()" может решить проблему.

person Michael J    schedule 19.02.2010

Вам нужно, чтобы ваш метод Proc был статическим методом.

person zabulus    schedule 18.02.2010
comment
OP говорит: Это должен быть любой класс, а указанный процесс не должен быть статичным. - person Alexey Malistov; 18.02.2010