dsch
asked on
Pointers to functions
Hi, I have created an RS232 class, but I want to change where the results are delivered to on the fly.
in the public: I have declared
void MyFunction(BYTE *,int );
void (*pDeliverData)(BYTE *,int );
Then on implementation
pDeliverData = MyFunction;//I get an error:
[C++ Error] rs232Thread.cpp(38): E2235 Member function must be called or its address taken.
So I then tried
pDeliverData = &MyFunction;//I then get the error:
[C++ Error] rs232Thread.cpp(38): E2034 Cannot convert 'void (* (_closure )(unsigned char *,int))(unsigned char *,int)' to 'void (*)(unsigned char *,int)'.
Ideally I want the thread that created the object to be able to assign a new return function.
Ant tips would be great, thanks.
David
in the public: I have declared
void MyFunction(BYTE *,int );
void (*pDeliverData)(BYTE *,int );
Then on implementation
pDeliverData = MyFunction;//I get an error:
[C++ Error] rs232Thread.cpp(38): E2235 Member function must be called or its address taken.
So I then tried
pDeliverData = &MyFunction;//I then get the error:
[C++ Error] rs232Thread.cpp(38): E2034 Cannot convert 'void (* (_closure )(unsigned char *,int))(unsigned char *,int)' to 'void (*)(unsigned char *,int)'.
Ideally I want the thread that created the object to be able to assign a new return function.
Ant tips would be great, thanks.
David
So MyFunction is member of the class?
If so the reason it fails is that signature of member class is different.
if you have
class A{
void f(BYTE*,int);
};
in reality f have a signature of void f(A*,BYTE*,int). See, the first argument of a member function is ALWAYS pointer to class it belongs to.
You can try solve this problem by trying to declaring MyFunction static.
Hope it helps..
If so the reason it fails is that signature of member class is different.
if you have
class A{
void f(BYTE*,int);
};
in reality f have a signature of void f(A*,BYTE*,int). See, the first argument of a member function is ALWAYS pointer to class it belongs to.
You can try solve this problem by trying to declaring MyFunction static.
Hope it helps..
>> See, the first argument of a member function
>> is ALWAYS pointer to class it belongs to.
That is not true. The procedure for passing the "this pointer" is impliementaion defined. It often is not passed in the same way as the other parameters.
dsch, what jkr and mblat hare saying is that a non-static member function is inheriently different than a free function (a non-member function or a static member function). The non-staitc member function takes a hidden parameter that the free function does not. The parameter is a pointer to the object for which the function is invoked. In other wirds, the "this" pointer is passed to the function as a hidden parameter. Free functions don't have this parameter, and thus can never be "equivalent" to a non-static member function.
For this reason, a pointer to a non-static member function can never be equivalent to, or convertable to, a pointer to a free function and vice versa.
Pointers to member functions have a unique syntax that is similar to, but different from pointers to free functions.
here is a short example of how pointers-to-members are declared and used
class Cls
{
int Add(int i1,int i2) { return i1 + i2 };
int Sub(int i1,int i2) { return i1 - i2 };
int Abs(int i) { return i <0? -1*i:i; };
}
// member function pointer typedef. Not
// necessary, except for readability.
typedef int (Cls::*MbrFunPtrTyp)(int,i nt);
// This type is a pointer to a member function of Cls that
// takes 2 ints as parameters and returns a int.
// Thus this type of pointer can point to Add() or Sub()
// but not to Abs().
// Declare and use a pointer of this type.
MbrFunPtrTyp FunPtr = &Cls::Add; // make pointer to add function.
Cls C; // Declare object of the class
Cls *CPtr = &C; // Declare pointer to object of the class.
int R1 = (C.*FunPtr)(1,2); // Add 1 and 2 using a Cls object.
int R2 = (CPtr->*FunPtr)(1,2); // Add 1 and 2 using a pointer to a Cls object.
FunPtr = &Cls::Sub; // Make pointer to Sub function.
int R3 = (C.*FunPtr)(1,2); // Subtract1 and 2 using a Cls object.
int R4 = (CPtr->*FunPtr)(1,2); // Subtract 1 and 2 using a pointer to a Cls object.
Note that the functions that the pointer-to-member pointer will be used with must have the same signature. To be precise they must:
1. be members of the same class.
2. have the same parameters.
3. have the same return value
4. Have the same calling convention.
Thus the example above the function pointer could be used with Add() and Sub(), but not with Abs(). You could define a seperate function pointer type that could be used with Abs() and other member functions of Cls that have the same parameters and signature etc.
>> is ALWAYS pointer to class it belongs to.
That is not true. The procedure for passing the "this pointer" is impliementaion defined. It often is not passed in the same way as the other parameters.
dsch, what jkr and mblat hare saying is that a non-static member function is inheriently different than a free function (a non-member function or a static member function). The non-staitc member function takes a hidden parameter that the free function does not. The parameter is a pointer to the object for which the function is invoked. In other wirds, the "this" pointer is passed to the function as a hidden parameter. Free functions don't have this parameter, and thus can never be "equivalent" to a non-static member function.
For this reason, a pointer to a non-static member function can never be equivalent to, or convertable to, a pointer to a free function and vice versa.
Pointers to member functions have a unique syntax that is similar to, but different from pointers to free functions.
here is a short example of how pointers-to-members are declared and used
class Cls
{
int Add(int i1,int i2) { return i1 + i2 };
int Sub(int i1,int i2) { return i1 - i2 };
int Abs(int i) { return i <0? -1*i:i; };
}
// member function pointer typedef. Not
// necessary, except for readability.
typedef int (Cls::*MbrFunPtrTyp)(int,i
// This type is a pointer to a member function of Cls that
// takes 2 ints as parameters and returns a int.
// Thus this type of pointer can point to Add() or Sub()
// but not to Abs().
// Declare and use a pointer of this type.
MbrFunPtrTyp FunPtr = &Cls::Add; // make pointer to add function.
Cls C; // Declare object of the class
Cls *CPtr = &C; // Declare pointer to object of the class.
int R1 = (C.*FunPtr)(1,2); // Add 1 and 2 using a Cls object.
int R2 = (CPtr->*FunPtr)(1,2); // Add 1 and 2 using a pointer to a Cls object.
FunPtr = &Cls::Sub; // Make pointer to Sub function.
int R3 = (C.*FunPtr)(1,2); // Subtract1 and 2 using a Cls object.
int R4 = (CPtr->*FunPtr)(1,2); // Subtract 1 and 2 using a pointer to a Cls object.
Note that the functions that the pointer-to-member pointer will be used with must have the same signature. To be precise they must:
1. be members of the same class.
2. have the same parameters.
3. have the same return value
4. Have the same calling convention.
Thus the example above the function pointer could be used with Add() and Sub(), but not with Abs(). You could define a seperate function pointer type that could be used with Abs() and other member functions of Cls that have the same parameters and signature etc.
ASKER
Hmmm, Thanks for this info, & I understand how to point to a member function, but what I am actually attempting to do, is pass INTO the Class pointer function.
Sorry this is hard to explain:
I have a Form which on activate creates an object (RS232 comms). The RS232 Object creates a new thread to monitor and deliver the incomming data.
I currently have it directly accessing the forms function:
Form1->DealWithData(S,Buff erSize); //S is a char*, BufferSize is the length og buffer. Yawn!
However this does not make it very portable, and I alos want to request data of different sizes and process it with a different function. So Ideally, I want to have the pointer to the function IN the class, so that when I call it (from within the class)(with the same parameters obviously) it delevers the data to the appropriate function.
ie the member function calls a function external to the class.
Does that explain it? I hope so.
Thanks again
David
Sorry this is hard to explain:
I have a Form which on activate creates an object (RS232 comms). The RS232 Object creates a new thread to monitor and deliver the incomming data.
I currently have it directly accessing the forms function:
Form1->DealWithData(S,Buff
However this does not make it very portable, and I alos want to request data of different sizes and process it with a different function. So Ideally, I want to have the pointer to the function IN the class, so that when I call it (from within the class)(with the same parameters obviously) it delevers the data to the appropriate function.
ie the member function calls a function external to the class.
Does that explain it? I hope so.
Thanks again
David
>> the member function calls a function external to the class.
That sounds like you are calling an ordinary free function. That is easy. I'm not sure what your problem is. We really need to see more of your code.
An example would be
// For convenience, declare a typedef for the pointer type.
typedef void (*FunctionPtrType)(BYTE *,int);
class X
{
FunctionPtrType Ptr; // The pointer to your function.
public:
SetPtr(FunctionPtrType P)
{
Ptr = p;
}
void Execute()
{
Ptr(SomePtr,5); // Make the call here.
}
};
That sounds like you are calling an ordinary free function. That is easy. I'm not sure what your problem is. We really need to see more of your code.
An example would be
// For convenience, declare a typedef for the pointer type.
typedef void (*FunctionPtrType)(BYTE *,int);
class X
{
FunctionPtrType Ptr; // The pointer to your function.
public:
SetPtr(FunctionPtrType P)
{
Ptr = p;
}
void Execute()
{
Ptr(SomePtr,5); // Make the call here.
}
};
ASKER
More Code.. Here goes:
HEADER FILE
//------------------------ ---------- ---------- ---------- ---------- ---------- -
#ifndef rs232ThreadH
#define rs232ThreadH
//------------------------ ---------- ---------- ---------- ---------- ---------- -
#include <Classes.hpp>
//------------------------ ---------- ---------- ---------- ---------- ---------- -
class RS232RXThread : public TThread
{
private:
HANDLE hCom;
DWORD dwError,eMask;
AnsiString *Str1;
void ShowLastError();
int FBufferSize;
int GetBufferSize()const;
void SetBufferSize(int);
protected:
void __fastcall Execute();
public:
void (*pDeliverData)(BYTE *,int );
__fastcall RS232RXThread(bool CreateSuspended,HANDLE hCom1);
__property int BufferSize = {read = GetBufferSize, write = SetBufferSize};
};
//------------------------ ---------- ---------- ---------- ---------- ---------- -
#endif
CPP FILE
//------------------------ ---------- ---------- ---------- ---------- ---------- -
#include <vcl.h>
#pragma hdrstop
#include "rs232Thread.h"
#include "Comms1.h"
#pragma package(smart_init)
//------------------------ ---------- ---------- ---------- ---------- ---------- -
__fastcall RS232RXThread::RS232RXThre ad(bool CreateSuspended, HANDLE hCom1)
: TThread(CreateSuspended),F BufferSize (0)
{
hCom = hCom1;
Str1 = new AnsiString();
}
//------------------------ ---------- ---------- ---------- ---------- ---------- -
void __fastcall RS232RXThread::Execute()
{
DWORD ByteCount;
char S[100];
bool Waiting = FALSE;
// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
DWORD dwCommEvent=0;
DWORD dwCommMask = 0;
//pDeliverData = &MyFunction;
OVERLAPPED osReader;
memset(&osReader,0,sizeof( OVERLAPPED ));
dwCommMask = EV_RXCHAR;
SetCommMask(hCom, dwCommMask);
DWORD lpErrors;
COMSTAT lpStat;
ByteCount = 1;
osReader.hEvent = CreateEvent(
NULL, // no security attributes
FALSE, // auto reset event
FALSE, // not signaled
NULL // no name
);
for(;;) {
if(!Waiting)
{
if (!WaitCommEvent(hCom, &dwCommEvent, &osReader))
{
if (GetLastError() == ERROR_IO_PENDING)
//overlapped I/O-operation cannot be completed immediately operation in background)
{
Waiting = TRUE;
}
}
}
else
{
ClearCommError(
hCom, // handle to communications device
&lpErrors, // error codes
&lpStat // communications status
);
if (lpStat.cbInQue >= BufferSize)//dwCommEvent & EV_RXCHAR)
{
if(ReadFile(hCom, &S, BufferSize/*lpStat.cbInQue */, &ByteCount, &osReader))
{
// A byte has been read; process it.
S[ByteCount] = 0;
Form1->DealWithData(S,Buff erSize); //Routine in calling thread
// To do.
}
else{ShowLastError();}
}
Waiting = FALSE;
dwCommEvent = 0;
//}
}// end else
}//end While
}//end of function
void RS232RXThread::ShowLastErr or()
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BU FFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSE RTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
int RS232RXThread::GetBufferSi ze()const
{
return FBufferSize;
}
void RS232RXThread::SetBufferSi ze(int Buf)
{
FBufferSize = Buf;
}
Form1->DealWithData(S,Buff erSize); is the routine outside that I want to call, but via pointer to the function.
Form1 is a TForm object in Borland VCL.
I want to pass in different functions but with the same parameters to receive the data.
HEADER FILE
//------------------------
#ifndef rs232ThreadH
#define rs232ThreadH
//------------------------
#include <Classes.hpp>
//------------------------
class RS232RXThread : public TThread
{
private:
HANDLE hCom;
DWORD dwError,eMask;
AnsiString *Str1;
void ShowLastError();
int FBufferSize;
int GetBufferSize()const;
void SetBufferSize(int);
protected:
void __fastcall Execute();
public:
void (*pDeliverData)(BYTE *,int );
__fastcall RS232RXThread(bool CreateSuspended,HANDLE hCom1);
__property int BufferSize = {read = GetBufferSize, write = SetBufferSize};
};
//------------------------
#endif
CPP FILE
//------------------------
#include <vcl.h>
#pragma hdrstop
#include "rs232Thread.h"
#include "Comms1.h"
#pragma package(smart_init)
//------------------------
__fastcall RS232RXThread::RS232RXThre
: TThread(CreateSuspended),F
{
hCom = hCom1;
Str1 = new AnsiString();
}
//------------------------
void __fastcall RS232RXThread::Execute()
{
DWORD ByteCount;
char S[100];
bool Waiting = FALSE;
// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
DWORD dwCommEvent=0;
DWORD dwCommMask = 0;
//pDeliverData = &MyFunction;
OVERLAPPED osReader;
memset(&osReader,0,sizeof(
dwCommMask = EV_RXCHAR;
SetCommMask(hCom, dwCommMask);
DWORD lpErrors;
COMSTAT lpStat;
ByteCount = 1;
osReader.hEvent = CreateEvent(
NULL, // no security attributes
FALSE, // auto reset event
FALSE, // not signaled
NULL // no name
);
for(;;) {
if(!Waiting)
{
if (!WaitCommEvent(hCom, &dwCommEvent, &osReader))
{
if (GetLastError() == ERROR_IO_PENDING)
//overlapped I/O-operation cannot be completed immediately operation in background)
{
Waiting = TRUE;
}
}
}
else
{
ClearCommError(
hCom, // handle to communications device
&lpErrors, // error codes
&lpStat // communications status
);
if (lpStat.cbInQue >= BufferSize)//dwCommEvent & EV_RXCHAR)
{
if(ReadFile(hCom, &S, BufferSize/*lpStat.cbInQue
{
// A byte has been read; process it.
S[ByteCount] = 0;
Form1->DealWithData(S,Buff
// To do.
}
else{ShowLastError();}
}
Waiting = FALSE;
dwCommEvent = 0;
//}
}// end else
}//end While
}//end of function
void RS232RXThread::ShowLastErr
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BU
FORMAT_MESSAGE_FROM_SYSTEM
FORMAT_MESSAGE_IGNORE_INSE
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
int RS232RXThread::GetBufferSi
{
return FBufferSize;
}
void RS232RXThread::SetBufferSi
{
FBufferSize = Buf;
}
Form1->DealWithData(S,Buff
Form1 is a TForm object in Borland VCL.
I want to pass in different functions but with the same parameters to receive the data.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
If it is in a class, there are methods to get it to work as a non-static member, but it's not a straight forward method.
Please post the function and your requirements.
Please post the function and your requirements.
ASKER
Forget MyFunction, this was remmed out a few hours ago.
I have just declared the member function as statis and it works now when calling the function pointer in the RS232Thread class.
I will now accept this as an answer.
Thanyou very much
David (and thanks jkr & mblat)
I have just declared the member function as statis and it works now when calling the function pointer in the RS232Thread class.
I will now accept this as an answer.
Thanyou very much
David (and thanks jkr & mblat)
ASKER
Great, I understand this so much more now.
Kind Regards
David
Kind Regards
David
void (MyClass::*pDeliverData)(B