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(); }

相关推荐
飞鸿踏雪(蓝屏选手)1 小时前
137 ≤ Chrome 主密钥获取研究
c++·chrome·windows·网络安全·逆向分析
洛水水2 小时前
【力扣100题】18.随机链表的复制
算法·leetcode·链表
南宫萧幕2 小时前
规则基 EMS 仿真实战:SOC 区间划分与 Simulink 闭环建模全解
算法·matlab·控制
多加点辣也没关系2 小时前
数据结构与算法|第二十三章:高级数据结构
数据结构·算法
庞轩px3 小时前
第七篇:Spring扩展点——如何优雅地介入Bean的创建流程
java·后端·spring·bean·aware·扩展点
tongluowan0074 小时前
一个请求在Spring MVC 中是怎么流转的
java·spring·mvc
hoiii1874 小时前
孤立森林 (Isolation Forest) 快速异常检测系统
算法
夜郎king5 小时前
Spring AI 对接大模型开发易错点总结与实战解决办法
java·人工智能·spring
oradh5 小时前
Oracle数据库中的Java概述
java·数据库·oracle·sql基础·oracle数据库java概述
组合缺一5 小时前
Java AI 框架三国杀:Solon AI vs Spring AI vs LangChain4j 深度对比
java·人工智能·spring·ai·langchain·llm·solon