空指针调用非静态成员函数虽能编译通过,但属未定义行为;若函数内访问非静态成员或隐式解引用this(如sizeof(*this)、dynamic_cast),必触发ub,多数情况段错误;虚函数调用必然崩溃;static成员函数无this,调用安全但语义不佳。

空指针调用非静态成员函数不会编译报错
编译器不禁止 p->func() 中 p 为 nullptr,因为 this 指针只是隐式传入的参数,和普通指针参数一样——传什么由调用者决定,编译器不做空值检查(除非启用 -fsanitize=undefined 或类似诊断)。
所以以下代码能通过编译:
class A {
public:
void foo() { cout foo(); // ✅ 编译通过,运行也可能不崩溃
- 只要
foo()内部不访问任何非静态成员(包括变量、函数、sizeof(*this)、dynamic_cast等需解引用 this 的操作),就不会触发段错误 - 一旦出现
this->x、this->bar()或任何隐式依赖对象状态的操作,就等同于nullptr->x,直接 UB(未定义行为),绝大多数情况是段错误 - 虚函数调用(
p->virtual_func())必然崩溃,因为要通过this去读取虚表指针
static 成员函数与 this 无关,但写法有误导风险
static 成员函数没有 this 指针,因此用空指针调用它完全安全,但语义上不推荐。
例如:
class A {
public:
static void bar() { cout bar(); // ✅ 运行安全,但容易让人误以为在操作对象
- 更清晰的写法是直接用作用域解析:
A::bar() -
p->bar()虽然合法,但掩盖了“该函数与对象实例无关”的事实,对维护者不友好 - 某些静态分析工具(如 clang-tidy)会警告这种用法
const 成员函数中 this 是 const T* const,空指针仍可能解引用
const 成员函数只限制你不能通过 this 修改对象状态,但不保证 this 非空。
例如:
class A {
int x = 42;
public:
void print() const { cout print(); // 崩溃
-
const修饰的是this所指对象的可变性,不是this本身的空安全性 - 即使函数体只读,只要访问了非静态成员,就依赖
this指向有效内存 - 如果真想支持空安全调用,必须显式判空:
if (!this) return;,但这属于手动防御,非常规做法
真正危险的是你以为“没访问成员”就安全
有些看似无害的操作,实际隐含对 this 的解引用,比如:
-
sizeof(*this):需要计算对象布局,若this == nullptr,*this是非法左值 -
typeid(*this):要求*this是多态类型的有效对象 -
dynamic_cast<derived>(this)</derived>:依赖虚表,空指针必崩 - 成员函数内调用另一个非静态成员函数(哪怕它自己也不访问成员):只要那个函数签名是非静态的,调用时就会把当前
this传过去,而它的实现可能悄悄访问了成员
最易被忽略的一点:现代 C++ 标准明确将空指针调用非静态成员函数定义为未定义行为(UB),哪怕函数体为空。所谓“侥幸运行成功”,只是特定编译器+优化级别+平台下的偶然现象,上线后换环境或加个 -O2 就可能翻车。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











