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

相关推荐
东小西7 小时前
【SAA实战】第 1 篇:ReactAgent 入门——先撸个"会调工具的助手"跑起来
java·人工智能·spring
兴通物联科技7 小时前
SMT PCB 微小 DataMatrix 码扫不动问题分析 兴通 XT8601B 600 万像素工业读码器落地实践
大数据·人工智能·单片机·嵌入式硬件·算法·计算机视觉
mqiqe7 小时前
AgentScope Java 2.0 协议集成全景解析:A2A、AG-UI、Agent Protocol 三大开放协议实战指南
java·开发语言·ui
脉动数据行情8 小时前
Java 实现台股 TWSE/TPEx 行情采集(个股 + K 线)
java·开发语言·twse·tpex·台股
月华路9 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
我想走路带风10 小时前
LRU和最长前缀和(计算机网络算法)
计算机网络·算法
M78佐菲10 小时前
Linux学习笔记:进程
linux·笔记·学习·算法
liangshanbo121510 小时前
虚拟列表深度面试题整理
java·开发语言·前端
gugucoding10 小时前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot