Function Pointers to Non-Static Object Methods | CodeGuru

Function Pointers to Non-Static Object Methods

One of the first things that I noticed when learning C++, was that function pointers had become much more difficult to use with object architecture. Each function/method needs to know what object it is part of.  So, to point to an object’s method, we also must know about an object. Using the data from each, we […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 2, 1999
4 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

One of the first things that I noticed when learning C++, was that function pointers
had become much more difficult to use with object architecture. Each function/method
needs to know what object it is part of.  So, to point to an object’s method, we also
must know about an object. Using the data from each, we can freely call any method of any
object, without knowing exactly what we are calling.

The code I have included is a holder class that takes a pointer to an object and a
pointer to a method.  Either can be changed at any time. During the lifetime of the
holder class object, a helper method can be called that calls the stored method pointer.
  Its that simple…Sort-of.  The syntax can get a little confusing, but I’ll
try to walk you through.

First, an abstract base class is defined.  The CMethodPtr class is derived from
this class, but this class is used to pass the data around between functions. You’ll see
what I mean later.

// R is the return type
template <class R>
class CMethodPtrBase
{
public:
    virtual R CallMethod() = 0;
    virtual R CallMethod(LPVOID arg1) = 0;
    virtual R CallMethod(LPVOID arg1, LPVOID arg2) = 0;
};

Next is the derived class.  Both the abstract base class and the derived class
require the return type of the function being held.  The derived class requires
another template argument declaring the type of object this holder will store. Neither of
these can be changed once the holder has been declared.

The constructor takes a pointer to the actual object( not the definition like above)
that contains the method we will call. It also takes a pointer to the method.  The
METHOD macro is used to easily pass the method into the holder.

The CallMethod() methods are the helper methods for calling the method that the holder
object contains.  The different versions are for different numbers of arguments.
  If more arguments are needed, then add new functions to the abstract base class and
to this class.

// r = return type
// o = object definition
// m = method
#define METHOD(r,o,m) (r (o::*)() )(&o::m)

// O = object definition
// R = return type
template <class O, class R>
class CMethodPtr : public CMethodPtrBase<R>
{
    typedef R (O::*PMETHOD)();
    typedef R (O::*PMETHOD1)(LPVOID);
    typedef R (O::*PMETHOD2)(LPVOID, LPVOID);

public:
    CMethodPtr(O* pObject, PMETHOD pMethod) : m_pObject( pObject ),
m_pMethod( pMethod ) {};

    // Member Variables
private:
    O*    m_pObject;    // pointer to an
object
    PMETHOD    m_pMethod;    // pointer to
the method

    //Implementation
public:
    void SetObject( O* pObject ) { m_pObject = pObject; }
    void SetMethod( PMETHOD pMethod ) { m_pMethod = pMethod; }

    // 0 args
    virtual R CallMethod()
    {
        return (m_pObject->*m_pMethod)();
    }

    // 1 arg
    virtual R CallMethod(LPVOID arg1)
    {
        return
(m_pObject->*(PMETHOD1)m_pMethod)(arg1);
    }

    // 2 args
    virtual R CallMethod(LPVOID arg1, LPVOID arg2)
    {
        return
(m_pObject->*(PMETHOD2)m_pMethod)(arg1, arg2);
    }
};

That is basically it for the definition.  Here is how it is used:

Somewhere declare the object that has the method we want to point to and the holder
object:

// A helper macro that uses the METHOD macro
#define SUMMETHOD(m) METHOD(int, CSumObject, m)

CSumObject m_SumObject;   // The object that has the method we want to point
to
CMethodPtr<CSumObject, int> m_SumMethodPtr( &m_SumObject, SUMMETHOD(Function2)
); // Uses a CSumObject thats returns an int

Function2() is the method that will be held. Later on we can call that function like
this:

int nArg1 = 5;
int nArg2 = 10;

int nReturn;

nReturn = m_SumMethod.CallMethod( &nArg1, &nArg2 );  // Whatever it was
pointing to, we just called it

If you want to pass a holder object through a function, define the function this way:

int MyObject::SomeFunction( CMethodPtrBase<int> pMethodPtr )
{
    return pMethodPtr->CallMethod();
}

Notice the abstract base class is used so that we do not have to know what type of
class the CMethodPtr object is holding.  If we used CMethodPtr directly, the template
arguments would require us to tell it what type of class the CMethodPtr object was
holding.

Take a look at the demo project or source to see a more thorough example.

Download demo project – 15.8 KB

Download source – 7.7 KB

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.