Pointers to non-static member functions, compiles with MSDEV, but not with GCC

J

John Doe

#include "project.h"


class ThatDoesProcessing;
typedef int (ThatDoesProcessing::*PFUNC)(int);


class ThatDoesProcessing {

public:

int ProcessThis( PFUNC pFunc ) {

int iRet = (this->*pFunc)( 2 );

return iRet;

}

};


class ThatNeedsToBeProcessed : public ThatDoesProcessing {

public:

void Test( void ) {

PFUNC pMyFunc;

pMyFunc = (PFUNC)CompareFunc;

ProcessThis( pMyFunc );

}

int CompareFunc( int i ) {

return i;

}

};


int _tmain( int /* argc */, TCHAR * /* argv[] */ ) {

ThatNeedsToBeProcessed b;

b.Test();

return 0;

}

---------------------------------------------------
The above compiles without any warnings or errors at all even
with warning level set to 4 with the MS compiler.

Compliling it with GCC version 3.3.1 (cygming special)
gives the following output:

$ make
g++ -O2 -fno-strength-reduce -I/cygdrive/m/include -I/usr/X11R6/include
-D__i386__ -DWIN32_LEAN_AND_MEAN -DX_LOCALE -D_X86_ -D__CYGWIN__
-D_XOPEN_SOURCE -D_POSIX_C_SOURCE=199309L -D_BSD_SOURCE
-D_SVID_SOURCE -D_GNU_SOURCE -c -o main.o main.cpp
main.cpp: In member function `void ThatNeedsToBeProcessed::Test()':
main.cpp:33: error: argument of type `int (ThatNeedsToBeProcessed::)(int)' does
not match `int (ThatDoesProcessing::*)(int)'
make: *** [main.o] Error 1

---------------------------------------------------

The error is on the line which reads

pMyFunc = (PFUNC)CompareFunc;

in ThatNeedsToBeProcessed::Test

I thought the whole idea of a cast was to coerce the compiler into seeing
one type as another, so why does it refuse to do so here? How do I get
around it?

Thanks in advance.
 
R

Ron Natalie

John Doe said:
I thought the whole idea of a cast was to coerce the compiler into seeing
one type as another, so why does it refuse to do so here? How do I get
around it?

Even if it compiled (which it shouldn't), your code exhibits undefined behavior. There's no
guarantee that it is going to work. You are not allowed to use the cast-bashed pointer
value until you cast it back to what it was before. The cast here is a reinterpret cast
and all you are guaranteed to be able to do is park the pointer value in the other pointer
and then cast it back to what it was before before you use it (you can also check it
against null).

It shouldn't even compile. You don't form pointer to members like you wrote it.
pMyFunc = reinterpret_cast<PFUNC>(&ThatNeedsToBeProcessed::CompareFunc);

The fact that you even need the cast is telling. If this were to work nicely the implicit
conversion would suffice. The problem is that not every member of the derived class
is valid in base (and specifically this one isn't).

How about a functor or something.
 
P

Paul M. Parks

The error is on the line which reads

pMyFunc = (PFUNC)CompareFunc;

in ThatNeedsToBeProcessed::Test

I thought the whole idea of a cast was to coerce the compiler into
seeing one type as another, so why does it refuse to do so here? How
do I get around it?


This seemed to do the trick for me:


START CODE --

// #include "project.h"
#include <iostream>

class ThatDoesProcessing;
typedef int (ThatDoesProcessing::*PFUNC)(int);

class ThatDoesProcessing
{
public:
int ProcessThis( PFUNC pFunc ) {
int iRet = (this->*pFunc)( 2 );
return iRet;
}

virtual int CompareFunc( int i ) {
std::cout << "Oops!" << std::endl;
return 0;
}

};


class ThatNeedsToBeProcessed : public ThatDoesProcessing
{
public:
void Test( void ) {
PFUNC pMyFunc;
pMyFunc = &ThatDoesProcessing::CompareFunc;
ProcessThis( pMyFunc );
}

virtual int CompareFunc( int i ) {
std::cout << "Made it!" << std::endl;
return i;
}

};


// I eliminated the _tmain and TCHAR here so I could
// build it.
int main( int /* argc */, char * /* argv[] */ )
{

ThatNeedsToBeProcessed b;
b.Test();
return 0;
}

-- END CODE

PMP
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

John Doe escribió:
#include "project.h"

class ThatDoesProcessing;
typedef int (ThatDoesProcessing::*PFUNC)(int);

class ThatDoesProcessing {

public:

int ProcessThis( PFUNC pFunc ) {

int iRet = (this->*pFunc)( 2 );

return iRet;

}

};

class ThatNeedsToBeProcessed : public ThatDoesProcessing {

public:

void Test( void ) {

PFUNC pMyFunc;

pMyFunc = (PFUNC)CompareFunc;

pMyFunc= (PFUNC) & ThatNeedsToBeProcessed::CompareFunc;

Regards.
 
L

lilburne

Ron said:
Much better...well formed and no undefined behavior.

The msdev compiler accepts a whole load of nonesense which
it ought to complain about. An example is:

int ff() {
return 0;
}

int main()
{
if (ff) { // this ought to have been 'if (ff()) {'
return 1;
}
return 0;
}
 
L

lilburne

jeffc said:
My current compiler allows that too.

Fortunately the sun solaris and irix compilers generate
warnings. Try turning up the warning level on your compiler
and force all warnings to be errors.
 
J

jeffc

lilburne said:
The msdev compiler accepts a whole load of nonesense which
it ought to complain about. An example is:

int ff() {
return 0;
}

int main()
{
if (ff) { // this ought to have been 'if (ff()) {'
return 1;
}
return 0;
}

My current compiler allows that too.
 
R

Ron Natalie

lilburne said:
The msdev compiler accepts a whole load of nonesense which
it ought to complain about. An example is:

int ff() {
return 0;
}

int main()
{
if (ff) { // this ought to have been 'if (ff()) {'

Perfectly valid C++. ff is the address of the function. The statement is always true.
 
L

lilburne

Ron said:
Perfectly valid C++. ff is the address of the function. The statement is always true.

It might be valid but it is never what was intended. Quite a
few compilers generate a warning.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,434
Messages
2,571,690
Members
48,796
Latest member
Greg L.

Latest Threads

Top