c++成员指针声明需指定类作用域:成员变量指针为类型 类名::*指针名,如int a::*p = &a::x;成员函数指针为返回类型 (类名::*指针名)(参数),如void (a::*f)() = &a::func;二者均存储偏移量而非地址,必须通过.*或->*结合对象调用。

成员指针怎么声明和初始化
C++里成员指针不是普通指针,它不存地址,而是存“偏移量”或“调用描述”,必须绑定到具体对象才能用。声明时语法怪,容易写错。
- 成员变量指针用
类型 类名::<em>指针名</em>,比如int A::p = &A::x; - 成员函数指针更复杂:
返回类型 (类名::<em>指针名)(参数列表)</em>,比如void (A::f)() = &A::func; - 初始化必须用取址符
&加作用域,&A::x合法,&x或A::x都编译不过 - 不能用
nullptr初始化后直接解引用,会未定义行为;但可以判空:if (p != nullptr)
怎么通过对象调用成员指针
成员指针本身不能单独运行,必须配合对象(或对象指针)使用,运算符是 .<em></em> 和 ->,不是 . 或 ->。
- 对象用
.<em></em>:比如a.p访问成员变量,a.*f()调用成员函数 - 对象指针用
-><em></em>:比如ptr->p、ptr->*f() - 注意括号优先级:
ptr-><em>f()</em>等价于(ptr->f)(),不是ptr->*(f());调用函数时务必加括号 - 静态成员不能用成员指针访问——它们没有 this 偏移,
&A::static_var直接报错
为什么 std::mem_fn 和 std::invoke 更安全
原生成员指针语法僵硬、易出错,尤其在泛型或容器中传参时。
-
std::mem_fn(&A::x)返回一个可调用对象,支持mem_fn(a)、mem_fn(ptr)统一写法,不用区分.<em></em>还是-> -
std::invoke(&A::func, a)或std::invoke(f, &a)自动识别调用方式,还能处理继承、重载、const 限定等边界情况 - 成员函数指针对 const/volatile 限定敏感:
void (A::<em>)()</em>和void (A::)() const是不同类型,传错就编译失败;而std::invoke在编译期做匹配校验
常见编译错误和坑
这些错误很典型,看到就能快速定位:
-
error: cannot convert 'int A::<em>' to 'int</em>' in initialization:把成员指针当普通指针用了,忘了它不能直接转成地址 -
error: '.<em>' applied to non-class type</em>:左边不是对象或对象引用,比如用了int x; x.p; -
error: must use '.<em>' or '-></em>' to call pointer-to-member function:写了p()或a.p(),漏了运算符 - 在模板中用
decltype推导成员指针类型时,注意它带完整限定,decltype(&A::x)是int A::<em></em>,不是int,别误当成普通指针类型做特化
成员指针的底层机制依赖编译器实现(比如多重继承下可能是多个偏移+调整函数),所以跨编译器或 ABI 不兼容时慎用裸指针;真要动态绑定逻辑,优先走 std::function + lambda 封装。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











