C++ 成员指针(Pointer to Member)完全指南


📘 C++ 成员指针(Pointer to Member)完全指南

核心思想 :成员指针不是普通指针,它指向的是"类中某个成员的位置(偏移量)",必须与具体对象结合才能使用


一、什么是成员指针?

C++ 允许你创建两种成员指针:

  1. 指向成员变量的指针
  2. 指向成员函数的指针

它们不存储内存地址 ,而是存储在类布局中的偏移信息 ,因此不能脱离对象单独使用


二、语法与声明

✅ 1. 指向成员变量的指针

cpp 复制代码
类型 类名::* 指针名;

示例

cpp 复制代码
class A {
public:
    int x;
    double y;
};

int A::* ptrX = &A::x;      // 指向 A 中的 int 成员 x
double A::* ptrY = &A::y;   // 指向 A 中的 double 成员 y

✅ 2. 指向成员函数的指针

cpp 复制代码
返回类型 (类名::*指针名)(参数列表);

示例

cpp 复制代码
class A {
public:
    void print();
    int add(int a, int b);
};

void (A::*func1)() = &A::print;           // 无参无返回
int (A::*func2)(int, int) = &A::add;     // 有参有返回

🔑 关键:

  • 必须使用 &类名::成员名 获取成员指针
  • 不能写 &成员名&A(类名不能取地址)

三、如何使用?------必须绑定对象!

成员指针不能单独调用或访问,必须通过以下两个专用运算符:

运算符 用途 示例
obj.*ptr 通过对象访问成员 obj.*ptrX
pObj->*ptr 通过对象指针访问成员 pObj->*ptrX

🧪 完整示例:

cpp 复制代码
A obj;
A* pObj = &obj;

// 访问成员变量
obj.*ptrX = 42;              // 等价于 obj.x = 42;
cout << pObj->*ptrY;         // 等价于 cout << obj.y;

// 调用成员函数
(obj.*func1)();              // 调用 obj.print()
int r = (pObj->*func2)(3,4); // 调用 obj.add(3,4)

⚠️ 注意括号!

obj.*func1() → 先调用 func1()(错误)

(obj.*func1)() → 先组合,再调用


四、关于 *ptr 的真相:它不是"解引用取值"!

这是最常见的误解!

❌ 错误理解:

"*ptr 是解引用,得到成员本身"

✅ 正确理解:

  • obj.*ptr 中,.* 是一个整体运算符(读作 "object dot star")
  • *ptr 不能独立存在,也不是传统意义上的"解引用"
  • 成员指针没有"值"的概念,只有"如何在一个对象上定位成员"的信息

💡 类比:
ptrX 就像一张"户型图上的标记:'主卧在此'"
obj 是一栋具体的楼
obj.*ptrX = "在这栋楼里,找到主卧"


五、常见错误与澄清

错误写法 为什么错 正确做法
*varPtr = &A; 1. &A 非法(类名不能取地址)2. *varPtr 不能单独赋值 obj.*varPtr = 100;
&A 类是类型,不是对象,无地址 &obj(对对象取地址)
funcPtr() 成员函数指针不能直接调用 (obj.*funcPtr)()
*funcPtr 无实际意义,不能调用 必须结合对象使用
int* p = &A::x; 成员指针 ≠ 普通指针,类型不匹配 int A::* p = &A::x;

六、&Class::member 到底是什么?

  • &A::x:获取 成员变量 x 在类 A 中的偏移信息
  • &A::func:获取 成员函数 func 在类 A 中的入口偏移
  • 它们不是内存地址,而是编译器内部用于定位成员的元数据
  • 类型分别为:
    • int A::*
    • void (A::*)()

✅ 所以 &Class::member获取成员指针的唯一合法方式


七、现代 C++ 建议:优先使用 Lambda

虽然成员指针是标准特性,但日常开发几乎不需要直接使用 。推荐用 lambda 表达式替代:

cpp 复制代码
A obj;

// 替代成员变量指针
auto getX = [&]() { return obj.x; };
auto setX = [&](int v) { obj.x = v; };

// 替代成员函数指针
auto callPrint = [&]() { obj.print(); };

// 可直接传给 std::function
std::function<void()> f = callPrint;

✅ 优势:

  • 语法简洁
  • 自动处理对象生命周期(注意引用捕获)
  • 编译器更容易优化
  • 避免 .* / ->* 的复杂语法

八、总结:一张表掌握全部

概念 说明 示例
成员指针类型 指向类成员的"偏移量",非内存地址 int A::*, void (A::*)()
获取方式 必须用 &类名::成员 &A::x, &A::print
使用方式 必须结合对象:obj.*ptrpObj->*ptr (obj.*func)()
*ptr 含义 不是解引用,是 .* 运算符的一部分 不能单独使用
&A 是否合法 ❌ 非法!类名不能取地址 &obj 才合法
现代替代方案 用 lambda + 捕获 [&]{ obj.f(); }

相关推荐
Sunsets_Red2 小时前
浅谈随机化与模拟退火
java·c语言·c++·python·算法·c#·信息学竞赛
Felven2 小时前
A. Add and Divide
数据结构·算法
Frostnova丶2 小时前
LeetCode 67. 二进制求和
算法·leetcode
上海锟联科技2 小时前
DAS 与 FBG 振动监测对比:工程应用中该如何选择?
数据结构·算法·分布式光纤传感
星火开发设计2 小时前
模板参数:类型参数与非类型参数的区别
java·开发语言·前端·数据库·c++·算法
JialBro2 小时前
【嵌入式】直流无刷电机FOC控制算法全解析
算法·嵌入式·直流·foc·新手·控制算法·无刷电机
昌兵鼠鼠2 小时前
LeetCode Hot100 哈希
学习·算法·leetcode·哈希算法
忘梓.2 小时前
二叉搜索树·极速分拣篇」:用C++怒肝《双截棍》分拣算法,暴打节点删除Boss战!
开发语言·c++·算法
星辰徐哥2 小时前
Java数组的定义、操作与应用场景
java·开发语言