Solved

pointer to overridden member function

Posted on 1999-01-18
12
303 Views
Last Modified: 2010-04-16
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
0
Comment
Question by:rlarner
  • 3
  • 3
  • 3
  • +2
12 Comments
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
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
0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
Oops I meant

"Member functions have an extra parameter, the this pointer "
0
 
LVL 15

Expert Comment

by:Tommy Hui
Comment Utility
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;
}

0
 
LVL 1

Author Comment

by:rlarner
Comment Utility
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)
0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
Sorry I misread your example.

I'll come back when I have some spare time
0
 

Expert Comment

by:DOMINIC011899
Comment Utility
#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

0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 1

Author Comment

by:rlarner
Comment Utility
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)

0
 

Expert Comment

by:DOMINIC011899
Comment Utility
I'll try it at home tonight, since at home, I have MSVC++ 6.0.
0
 

Expert Comment

by:DOMINIC011899
Comment Utility
// 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:


0
 

Accepted Solution

by:
resin earned 400 total points
Comment Utility
Hi,
I also tried Biju's implementation, which cannot be compiled on my VC++6.0.
Following code can be compiled and I hope it helps.
============================
#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, class FPSave>
bool SaveUtl(CToSave *pToSave,
            CSaver *pSaver,
            FPSave Save)
{
    return (pToSave->*Save)(pSaver);
}

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

    bool retVal;
    // blah..blah..
    // this line works:  
    // -- really, I think it just goes through compiling,
    // -- but it doesn't work ;-)
    // bool retVal = SaveUtl(&bar, &file, bar.*Bar::Save);
    retVal = SaveUtl(&bar, &file, &Bar::Save);

    // the next line is the one that the compiler complains about.
    // retVal = SaveUtl(&foo, &file, (foo.*Foo::Save)(File*));
    bool (Foo::*fpFile)(File*) = &Foo::Save;
    bool (Foo::*fpBar)(Bar*) = &Foo::Save;
    retVal = SaveUtl(&foo, &file, fpFile);
    retVal = SaveUtl(&foo, &bar, fpBar);
    return 0;
}
0
 
LVL 1

Author Comment

by:rlarner
Comment Utility
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!
0
 

Expert Comment

by:resin
Comment Utility
I had not seen Dominic's last answer before I began to work on it. I admit Dominic's answer is better mine.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now