CodeNebula
C++98corebeginner

Pointers to Members

C++98 · The Foundation · Compiler flag: -std=c++98

Explanation

Pointers that refer to a specific data member or member function of a class.

Real-World Scenario

Iterate over different fields of a struct in a serialization library.

Quick Snippet

snippet.cpp
struct S { int x; }; int S::*p = &S::x; S s; s.*p = 42;

Full Example

pointers_to_members.cpp
// CodeNebula - C++98 Example: Pointers to Members
// Compile: g++ -std=c++98 -Wall -Wextra -o example pointers_to_members.cpp

// Demonstrates pointers to class members in C++98: pointer to data member,
// pointer to member function, using .* and ->* operators, arrays of member
// pointers, and practical uses.

#include <iostream>
#include <cstring>

// ------------------------------------------------------------------
// A class to demonstrate member pointers
// ------------------------------------------------------------------
class Student {
public:
    char name[30];
    int  age;
    double gpa;

    Student(const char* n, int a, double g)
        : age(a), gpa(g)
    {
        std::strncpy(name, n, 29);
        name[29] = '\0';
    }

    void introduce() const
    {
        std::cout << "    Hi, I'm " << name << ", age " << age
                  << ", GPA " << gpa << std::endl;
    }

    void study(const char* subject) const
    {
        std::cout << "    " << name << " is studying " << subject << std::endl;
    }

    double getGpa() const { return gpa; }
    int    getAge() const { return age; }
};

// ------------------------------------------------------------------
// Another class for member function pointer variety
// ------------------------------------------------------------------
class Calculator {
public:
    int value;

    Calculator() : value(0) {}
    Calculator(int v) : value(v) {}

    int add(int x) { value += x; return value; }
    int sub(int x) { value -= x; return value; }
    int mul(int x) { value *= x; return value; }

    void reset() { value = 0; }

    void print() const
    {
        std::cout << "    value = " << value << std::endl;
    }
};

int main()
{
    // ------------------------------------------------------------------
    // 1. Pointer to data member
    // ------------------------------------------------------------------
    std::cout << "=== Pointer to Data Member ===" << std::endl;

    // Declare a pointer to an int member of Student
    int Student::*pAge = &Student::age;

    // Declare a pointer to a double member of Student
    double Student::*pGpa = &Student::gpa;

    Student alice("Alice", 20, 3.8);

    // Use .* operator with an object
    std::cout << "  alice.*pAge = " << alice.*pAge << std::endl;
    std::cout << "  alice.*pGpa = " << alice.*pGpa << std::endl;

    // Modify through member pointer
    alice.*pAge = 21;
    alice.*pGpa = 3.9;
    std::cout << "  After modification:" << std::endl;
    std::cout << "  alice.*pAge = " << alice.*pAge << std::endl;
    std::cout << "  alice.*pGpa = " << alice.*pGpa << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. Pointer to data member with ->* (pointer to object)
    // ------------------------------------------------------------------
    std::cout << "=== Using ->* Operator ===" << std::endl;

    Student* pStudent = &alice;

    // Use ->* operator with a pointer to object
    std::cout << "  pStudent->*pAge = " << pStudent->*pAge << std::endl;
    std::cout << "  pStudent->*pGpa = " << pStudent->*pGpa << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Pointer to member function (no parameters, const)
    // ------------------------------------------------------------------
    std::cout << "=== Pointer to Member Function ===" << std::endl;

    // Declare a pointer to a const member function: void (Student::*)() const
    void (Student::*pIntroduce)() const = &Student::introduce;

    Student bob("Bob", 22, 3.5);

    // Call using .* with an object
    std::cout << "  alice.introduce() via pointer:" << std::endl;
    (alice.*pIntroduce)();

    std::cout << "  bob.introduce() via pointer:" << std::endl;
    (bob.*pIntroduce)();

    // Call using ->* with a pointer to object
    Student* pBob = &bob;
    std::cout << "  pBob->introduce() via pointer:" << std::endl;
    (pBob->*pIntroduce)();
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Pointer to member function with parameters
    // ------------------------------------------------------------------
    std::cout << "=== Member Function Pointer with Parameters ===" << std::endl;

    void (Student::*pStudy)(const char*) const = &Student::study;

    (alice.*pStudy)("Mathematics");
    (bob.*pStudy)("Physics");
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. Switching between member pointers (data members)
    // ------------------------------------------------------------------
    std::cout << "=== Switching Data Member Pointers ===" << std::endl;

    Student students[] = {
        Student("Alice", 20, 3.8),
        Student("Bob", 22, 3.5),
        Student("Carol", 19, 3.9)
    };

    // Print a specific field for all students using a member pointer
    std::cout << "  Ages: ";
    int Student::*field = &Student::age;
    for (int i = 0; i < 3; ++i) {
        std::cout << students[i].*field << " ";
    }
    std::cout << std::endl;

    std::cout << "  GPAs: ";
    double Student::*dfield = &Student::gpa;
    for (int i = 0; i < 3; ++i) {
        std::cout << students[i].*dfield << " ";
    }
    std::cout << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 6. Array of member function pointers (Calculator)
    // ------------------------------------------------------------------
    std::cout << "=== Array of Member Function Pointers ===" << std::endl;

    // Pointer to member function: int (Calculator::*)(int)
    typedef int (Calculator::*CalcOp)(int);

    CalcOp ops[] = { &Calculator::add, &Calculator::sub, &Calculator::mul };
    const char* opNames[] = { "add", "sub", "mul" };

    Calculator calc(10);
    std::cout << "  Starting value: ";
    calc.print();

    for (int i = 0; i < 3; ++i) {
        int result = (calc.*ops[i])(5);
        std::cout << "  After " << opNames[i] << "(5): result = " << result;
        std::cout << ", ";
        calc.print();
    }
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 7. Pointer to member function returning value
    // ------------------------------------------------------------------
    std::cout << "=== Member Function Returning Value ===" << std::endl;

    double (Student::*getter)() const;

    // Point to getGpa
    getter = &Student::getGpa;
    std::cout << "  GPAs via pointer to getGpa():" << std::endl;
    for (int i = 0; i < 3; ++i) {
        std::cout << "    " << students[i].name << ": "
                  << (students[i].*getter)() << std::endl;
    }
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 8. Practical: generic "print field" function using member pointer
    // ------------------------------------------------------------------
    std::cout << "=== Generic Field Printer ===" << std::endl;

    // Print a table of student data using member pointers
    std::cout << "  Name          Age   GPA" << std::endl;
    std::cout << "  --------------------------" << std::endl;

    int Student::*agePtr = &Student::age;
    double Student::*gpaPtr = &Student::gpa;

    for (int i = 0; i < 3; ++i) {
        std::cout << "  ";
        // Print name (fixed width, manual padding)
        int nameLen = static_cast<int>(std::strlen(students[i].name));
        std::cout << students[i].name;
        for (int j = nameLen; j < 14; ++j) std::cout << ' ';

        std::cout << students[i].*agePtr << "    "
                  << students[i].*gpaPtr << std::endl;
    }
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 9. sizeof member pointers
    // ------------------------------------------------------------------
    std::cout << "=== sizeof Member Pointers ===" << std::endl;
    std::cout << "  sizeof(int Student::*)                : "
              << sizeof(int Student::*) << std::endl;
    std::cout << "  sizeof(void (Student::*)() const)     : "
              << sizeof(void (Student::*)()) << std::endl;
    std::cout << "  sizeof(int (Calculator::*)(int))      : "
              << sizeof(int (Calculator::*)(int)) << std::endl;
    std::cout << "  sizeof(int*)  (regular pointer)       : "
              << sizeof(int*) << std::endl;
    std::cout << "  (Member pointers may be larger than regular pointers)" << std::endl;

    return 0;
}

/*
Expected output:

=== Pointer to Data Member ===
  alice.*pAge = 20
  alice.*pGpa = 3.8
  After modification:
  alice.*pAge = 21
  alice.*pGpa = 3.9

=== Using ->* Operator ===
  pStudent->*pAge = 21
  pStudent->*pGpa = 3.9

=== Pointer to Member Function ===
  alice.introduce() via pointer:
    Hi, I'm Alice, age 21, GPA 3.9
  bob.introduce() via pointer:
    Hi, I'm Bob, age 22, GPA 3.5
  pBob->introduce() via pointer:
    Hi, I'm Bob, age 22, GPA 3.5

=== Member Function Pointer with Parameters ===
    Alice is studying Mathematics
    Bob is studying Physics

=== Switching Data Member Pointers ===
  Ages: 20 22 19
  GPAs: 3.8 3.5 3.9

=== Array of Member Function Pointers ===
  Starting value:     value = 10
  After add(5): result = 15,     value = 15
  After sub(5): result = 10,     value = 10
  After mul(5): result = 50,     value = 50

=== Member Function Returning Value ===
  GPAs via pointer to getGpa():
    Alice: 3.8
    Bob: 3.5
    Carol: 3.9

=== Generic Field Printer ===
  Name          Age   GPA
  --------------------------
  Alice         20    3.8
  Bob           22    3.5
  Carol         19    3.9

=== sizeof Member Pointers ===
  sizeof(int Student::*)                : 4 (or 8)
  sizeof(void (Student::*)() const)     : 8 (or 16)
  sizeof(int (Calculator::*)(int))      : 8 (or 16)
  sizeof(int*)  (regular pointer)       : 4 (or 8)
  (Member pointers may be larger than regular pointers)
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example pointers_to_members.cpp