Link to home
Start Free TrialLog in
Avatar of rlarner
rlarner

asked on

pointer to overridden member function

I am trying to write a helper template function that takes a pointer to a member function.  In most cases the template works - however, when the member function I am trying to get the address of is overloaded, the compiler understandably complains.  How can I retrieve the address of an overloaded  member function?

Here is an example (never compiled, but might give you and idea):

class Bar
{
public:
    bool Save(File*);
};

class Foo
{
public:
    bool Save(File*);
    bool Save(Bar*);
};

template <class CToSave, class CSaver>
    SaveUtl(CToSave *pToSave,
            CSaver *pSaver,
            bool CToSave::*Save(CSaver*))
{
    pToSave->*Save(pSaver);
}

main()
{
    Foo foo;
    Bar bar;
    File file;

// blah..blah..
// this line works:
    bool retVal = SaveUtl(&bar, &file, bar.*Bar::Save);

// the next line is the one that the compiler complains about.
    bool retVal = SaveUtl(&foo, &file, foo.*Foo::Save);
}

If it helps/hinders at all, I am using MS Visual C++ Version 6.0. (and no comments from the peanut gallery! <sigh>)

Thanks!

Rusty Larner
Avatar of Answers2000
Answers2000

Non-Member functions have an extra parameter, the this pointer  This is why your code doesn't work as expected (I'm surprised it works at all).

The compiler is also free to change the parameter stack to suit its needs (not yours).
 
My suggestion is to make the member function static (unfortunately you can't virtual it), or make a pointer to the class, and then call a virtual member function.

You probably won't like this, so I'll make it a comment
Oops I meant

"Member functions have an extra parameter, the this pointer "
It seems like the intent is to create a template function that knows how to save anything that is passed in. If that is the case, why have the extra parameter for the template function?

Here's a simpler version:

#include <iostream>

using namespace std;

class File
{
};

class Bar
{
public:
    bool Save(File*)
    {
          cout << "Bar::Save file" << endl;
            return true;
    }
};

class Foo
{
public:
    bool Save(File*)
    {
          cout << "Foo::Save file" << endl;
            return true;
    }

    bool Save(Bar*)
    {
          cout << "Foo::Save bar" << endl;
            return true;
    }
};

template <class CToSave, class CSaver>
SaveUtl(CToSave *pToSave, CSaver *pSaver)
{
    pToSave->Save(pSaver);
}

main()
{
    Foo foo;
    Bar bar;
    File file;

// blah..blah..
// this line works:
    bool retVal = SaveUtl(&bar, &file);

// the next line is the one that the compiler complains about.
    retVal = SaveUtl(&foo, &bar);
    retVal = SaveUtl(&foo, &file);

      return 0;
}

Avatar of rlarner

ASKER

I'm sorry - the example I gave was very simplified from the actual situation.  Here's some more details:
* The classes I am trying to work with are defined outside of the scope of my control, so I am unable to change how they work.
* The member function(s) I am trying to call may have different names (e.g. Save, Write, etc.), so I need the pointer to member function.

Answers 2000: Getting a pointer to member function (note: this is different from a function pointer!) is valid in C++. (that is the use for the ->* operator)  See ARM 5.5, I believe.  Also, Q108-Q112 in the C++ faq (I found it at http://www.cs.bsu.edu/homepages/peb/cplusplus/FAQ/section17.html)
Sorry I misread your example.

I'll come back when I have some spare time
#include <IOSTREAM>
using namespace std;

// I should create this so it will compile
class File
      {
      public:
      int n;
      };

class Bar
      {
      public:
        bool Save( File* )
            {
            return true;
            }
      };

class Foo
      {
      public:
        bool Save( File* )
            {
            return true;
            }
            
        bool Save( Bar* )
            {
            return true;
            }
      };


template <class CToSave, class CSaver>
bool SaveUtl(
      CToSave *pToSave,
      CSaver  *pSaver,
      bool (CToSave::*Save)(CSaver *) // I added parentheses
      )
{
    (pToSave->*Save)( pSaver ); // I added parentheses
      return true;
}

void main()
{
    Foo foo;
    Bar bar;
    File file;

    bool retVal = SaveUtl( &bar, &file, &Bar::Save );
    //bool retVal = SaveUtl( &bar, &file, bar.*Bar::Save );

    // Declare pfnSave as a pointer to a member of Foo that
    //    accepts a File * (or Bar *, whichever you want)
    bool (Foo::*pfnSave)(File*) = &Foo::Save;
    // Then pass pfnSave instead of a direct &Foo::Save
    retVal = SaveUtl( &foo, &file, pfnSave );
}

//  I hope this helps

Avatar of rlarner

ASKER

Thanks, Dominik - but your suggestion does not compile for me (and I believe it would not work).  MS Visual C++ 6.0 gives an error in the template when I try to call the function pointer using the variable initialized with the &(class::fn) value.  And, the format you are using takes the address of a function - not a pointer to a member function, which is a very different concept.  The compiler will allow a typecast from one to the other (which is why the assignment was allowed), but its usage is undefined after that.  (This may be why your compiler did not complain and mine did)

I'll try it at home tonight, since at home, I have MSVC++ 6.0.
// The following console program
// compiles perfectly in Visual C++ 6.0
// I challenge anyone who has Visual C++ 6.0 to cut and
// paste the following, compile and run it.


#include <IOSTREAM>
using namespace std;


class File
    {
    public:
    int n;
    };


class Bar
    {
    public:
    bool Save( File * )
        {
        cout << "Inside Bar's Save( File * )" << endl;
        return true;
        }
    };


class Foo
    {
    public:
    bool Save( File * )
        {
        cout << "Inside Foo's Save( File * )" << endl;
        return true;
        }

    bool Save( Bar * )
        {
        cout << "Inside Foo's Save( Bar * )" << endl;
        return true;
        }
    };




template <class CToSave, class CSaver>
bool SaveUtl( CToSave *pToSave, CSaver *pSaver,
    bool (CToSave::*Save)( CSaver * )
    )
    {
    (pToSave->*Save)( pSaver );
    return true;
    }


void main()
    {
    Foo foo;
    Bar bar;
    File file;

    bool retVal = SaveUtl( &bar, &file, &Bar::Save );

    //    Declare pfnSaveFile as a pointer to a member of
    //        Foo that accepts a File *
    bool (Foo::*pfnSaveFile)( File * ) = &Foo::Save;

    //    Then pass pfnSaveFile instead of a direct &Foo::Save
    //    This should call Foo's bool Save( File * ) method
    retVal = SaveUtl( &foo, &file, pfnSaveFile );

    //    Declare pfnSaveBar as a pointer to a member of
    //        Foo that accepts a Bar *
    bool (Foo::*pfnSaveBar)( Bar * ) = &Foo::Save;

    //    Then pass pfnSaveBar instead of a direct &Foo::Save
    //    This should call Foo's bool Save( Bar * ) method
    retVal = SaveUtl( &foo, &bar, pfnSaveBar );

    //    Pause the console program
    cout << "\npress <enter> to end.";
    cin.get();
    }

//The following is the exact result:
//
//Inside Bar's Save( File * )
//Inside Foo's Save( File * )
//Inside Foo's Save( Bar * )
//
//press <enter> to end.
//
// As you can see, you can even choose which
// overloaded member function to invoke.
//
// rlarner, I do not where you got your syntax in addressing
// pointers to members.  I got mine from the documentation of
// Visual C++ 6.0 itself as I cut and paste below.  I am not
// using ordinary pointers to functions, I am using pointers to
// members as indicated by the operators ->* and .* on the above
// code.

======== The following is the doc for pointers to members ====

Pointers to Members
Declarations of pointers to members are special cases of pointer declarations.

Syntax

decl-specifiers class-name :: * cv-qualifier-listopt dname ;

A pointer to a member of a class differs from a normal pointer because it has type information for the type of the member and for the class to which the member belongs. A normal pointer identifies (has the address of) only a single object in memory. A pointer to a member of a class identifies that member in any instance of the class. The following example declares a class, Window, and some pointers to member data.

class Window
{
public:
    Window();                               // Default constructor.
    Window( int x1, int y1,                 // Constructor specifying
        int x2, int y2 );                   //  window size.
    BOOL SetCaption( const char *szTitle ); // Set window caption.
    const char *GetCaption();               // Get window caption.
    char *szWinCaption;                     // Window caption.
};

// Declare a pointer to the data member szWinCaption.
char * Window::* pwCaption = &Window::szWinCaption;

In the preceding example, pwCaption is a pointer to any member of class Window that has type char*. The type of pwCaption is char * Window::*. The next code fragment declares pointers to the SetCaption and GetCaption member functions.

const char * (Window::*pfnwGC)() = &Window::GetCaption;
BOOL (Window::*pfnwSC)( const char * ) = &Window::SetCaption;

The pointers pfnwGC and pfnwSC point to GetCaption and SetCaption of the Window class, respectively. The code copies information to the window caption directly using the pointer to member pwCaption:


ASKER CERTIFIED SOLUTION
Avatar of resin
resin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rlarner

ASKER

Great - two answers that both work! <sigh>

Dominic - your fix was first in and more correct (it still has the function pointers declared in the template).  I will be posting a seperate question for you for 500 points in this forum as soon as I am done with this question.

Resin - I am accepting your answer to get this saved (and finished!)  Thanks for the effort!
I had not seen Dominic's last answer before I began to work on it. I admit Dominic's answer is better mine.