REW

What Is A Function Pointer Inside A Class?

Published Aug 29, 2025 6 min read
On this page

A function pointer inside a class, more formally known as a pointer to a member function, is a special type of pointer used in C++ to refer to a non-static member function of a specific class. Unlike a regular function pointer that points to a global or static function, a member function pointer must be associated with an object of the class to be invoked. This is because non-static member functions operate on instance-specific data and require an implicit this pointer to access that data.

This mechanism is a cornerstone of advanced C++ features like callback systems, command patterns, and dynamic dispatch that don't rely on virtual functions. While the syntax can appear convoluted, understanding the underlying principles reveals a powerful tool for creating flexible and modular designs.

Member function pointers versus regular function pointers

The key difference between a regular function pointer and a member function pointer is the concept of an object instance.

  • Regular Function Pointer: Points to a function that exists globally or is defined as static inside a class. These functions do not require an object instance to be called.
  • Member Function Pointer: Points to a non-static member function, which means it requires an instance of the class (the this pointer) to be invoked. The pointer itself does not contain the this pointer, which is supplied at the time of the call.

The compiler handles this distinction by treating member function pointers as a unique type that includes the class scope. The size and internal representation of a member function pointer can vary between compilers, as they may need to store additional information, especially for virtual functions.

Syntax for non-static member function pointers

The syntax for declaring, initializing, and invoking member function pointers is unique and can be broken down into three main parts.

1. Declaration

To declare a pointer to a member function, you must specify the class name and use the scope resolution operator (::). The pointer name must be wrapped in parentheses to clarify that the asterisk (*) is part of the pointer declaration and not the function's return type.

class MyClass {
public:
    void myMethod(int);
};
void (MyClass::*ptr_to_member)(int); // Declaration

Use code with caution.

2. Assignment

When assigning a member function to the pointer, you must use the address-of operator (&) along with the class name and scope resolution operator.

ptr_to_member = &MyClass::myMethod; // Assignment

Use code with caution.

3. Invocation

Calling the function through the pointer requires an instance of the class. You can use one of two special operators:

  • .* (dot-star): Used with an object instance.
  • ->* (arrow-star): Used with a pointer to an object.
#include <iostream>
class MyClass {
public:
    void myMethod(int value) {
        std::cout << "Value: " << value << std::endl;
    }
};
int main() {
    // 1. Declare the member function pointer type
    using MemberFunctionPtr = void (MyClass::*)(int);
    // 2. Create an instance of the class and a pointer
    MyClass obj;
    MyClass* ptr_obj = &obj;
    // 3. Assign the member function
    MemberFunctionPtr ptr_to_member = &MyClass::myMethod;
    // 4. Invoke the function using the object or a pointer
    (obj.*ptr_to_member)(10);     // Invocation with an object
    (ptr_obj->*ptr_to_member)(20); // Invocation with an object pointer
    return 0;
}

Use code with caution.

Output:

Value: 10
Value: 20

Static member function pointers

Static member functions behave like regular, non-member functions because they are not associated with a specific object instance and have no this pointer. As a result, you can use a regular function pointer to store their address, though you must still specify the class scope.

#include <iostream>
class MyClass {
public:
    static void staticMethod(const char* msg) {
        std::cout << "Static message: " << msg << std::endl;
    }
};
int main() {
    // Use a regular function pointer for a static member function
    void (*ptr_to_static_method)(const char*);
    // The address-of operator is optional for non-member functions,
    // but required for member functions. It's good practice to use it.
    ptr_to_static_method = &MyClass::staticMethod;
    ptr_to_static_method("Hello from static");
    return 0;
}

Use code with caution.

Output:

Static message: Hello from static

Pointers to virtual member functions

A pointer to a virtual member function behaves exactly as expected, leveraging the dynamic dispatch mechanism of virtual functions. When you invoke a virtual function through a member function pointer, the correct overridden version is called based on the object's actual runtime type, not the pointer's static type.

#include <iostream>
class Base {
public:
    virtual void show() {
        std::cout << "Base show" << std::endl;
    }
};
class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived show" << std::endl;
    }
};
int main() {
    using MemberFunctionPtr = void (Base::*)();
    Base base_obj;
    Derived derived_obj;
    MemberFunctionPtr ptr_to_show = &Base::show;
    // The virtual dispatch mechanism is triggered, and the correct function is called.
    (base_obj.*ptr_to_show)();
    (derived_obj.*ptr_to_show)();
    return 0;
}

Use code with caution.

Output:

Base show
Derived show

Modern alternatives: std::function and lambdas

While pointers to member functions are powerful, their syntax can be cumbersome. Modern C++ provides more flexible and safer alternatives like std::function and lambda expressions.

Using std::function

The std::function template can wrap any callable object, including function pointers, lambdas, and member functions, providing a uniform interface. When wrapping a member function, you must bind it to a specific object instance using std::bind or a lambda.

#include <iostream>
#include <functional>
class MyClass {
public:
    void myMethod(int value) {
        std::cout << "std::function call: " << value << std::endl;
    }
};
int main() {
    MyClass obj;
    // Use a lambda to capture the object and call the member function
    std::function<void(int)> func = [&](int val) {
        obj.myMethod(val);
    };
    func(42);
    return 0;
}

Use code with caution.

Output:

std::function call: 42

Using lambda expressions

Lambdas are a concise way to create anonymous function objects. They are often the most straightforward solution for creating callbacks or representing function objects, as they can capture the this pointer automatically.

#include <iostream>
class MyClass {
public:
    void myMethod(int value) {
        std::cout << "Lambda call: " << value << std::endl;
    }
    void someFunction() {
        // Create a lambda that captures 'this' and calls a member function
        auto lambda_func = [this](int val) {
            this->myMethod(val);
        };
        lambda_func(100);
    }
};
int main() {
    MyClass obj;
    obj.someFunction();
    return 0;
}

Use code with caution.

Output:

Lambda call: 100

When to use pointers to member functions

While modern alternatives are often preferred, there are specific scenarios where classic member function pointers are still relevant:

  • Interfacing with C APIs: Many C libraries use function pointers for callbacks. While modern C++ wrappers can be built, understanding the underlying mechanism is crucial for low-level integration.
  • Compile-time efficiency: For performance-critical code, a raw member function pointer can sometimes offer a slight performance advantage over std::function by avoiding the overhead of type erasure.
  • Legacy codebases: Maintaining and extending older C++ code often requires a deep understanding of these classic language features.

In most modern C++ applications, std::function and lambdas are the recommended approach for creating flexible and maintainable code. However, the pointer to a member function remains a foundational concept that showcases the power and complexity of C++'s object model.

Enjoyed this article? Share it with a friend.