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.*ptr 或 pObj->*ptr (obj.*func)()
*ptr 含义 不是解引用,是 .* 运算符的一部分 不能单独使用
&A 是否合法 ❌ 非法!类名不能取地址 ✅ &obj 才合法
现代替代方案 用 lambda + 捕获 [&]{ obj.f(); }

相关推荐
2301_780789664 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
Sakura_j_h_5 小时前
EasyEDA PCB 快速设计Skills
c++·python·github
学长毕设5 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
ZhengEnCi6 小时前
Agent 架构怎么选:从单 Agent 到多 Agent 编排的选型决策指南
算法·架构
步行cgn6 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川6 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵6 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
程序喵大人6 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
秋天的怀念_David6 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas1007 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品