开发者

Converting method signatures

typedef void (__thiscall* LPVOIDPROC) (void);

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
  }
}

How to get rid of this error C2440: 'type cast' : cannot convert from 'void (__thiscall ClassB::* )(void)' to 'LPVOIDPROC' ? I don't want to limit LPVOIDPROC signature to ClassB only. This should be any class and referenced proc should not be static.


Workaround:

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>);      
 } 
};


I refer you to this link. Your type LPVOIDPROC is a pointer-to-function, which is not the same thing as a pointer-to-member-function. When you try to cast ClassB::Proc, you are trying to convert a pointer-to-member-function, an invalid operation.

You should take a look at boost::function, that offers exactly what you are looking for. Or you could use functors to encapsulate your functions if you don't want to resort to boost. Example:

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() }


Non-static methods require a 'this' pointer, without a 'this' pointer you cannot call it, and so it makes no sense to cast it to a C function pointer.

Consider making a simple class (let's call it X) that has

  • a data member that refers to a ClassB instance
  • a () operator (although I prefer methods with clear names) calling ClassB::Proc using the ClassB instance as this-pointer.

Instead of passing a function pointer to class A, make an instance of X (with its datamember to ClassB filled in) and pass this to class A. Instead of calling a function pointer class A should call x().

Class X could even be written using templates, so if you have this situation for more than one class you must only write it once.

I think that in C# it can be done cleaner using delegates but I leave that to the C# and .Net specialists.


  1. Never cast function pointers. You can end up with stack corruption. Don't do it.

  2. Don't pass pointers to non-static member functions. They use a different calling convention and are not compatible.

  3. In your case, making "Proc()" static might solve the problem.


You need your Proc method to be a static method.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜