C++中空指针访问成员函数

一、核心结论先明确

空指针(nullptr/NULL)可以调用类的非静态成员函数,但有一个严格前提:

函数内部没有通过this指针访问任何非静态成员变量 / 调用依赖成员变量的函数。

一旦访问成员变量,就会触发 "空指针解引用",程序直接崩溃(段错误)。

二、代码示例:空指针调用成员函数的两种情况

  1. 能正常调用的情况(函数内不访问成员变量)
cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age; // 非静态成员变量

    // 情况1:成员函数仅打印固定内容,不访问任何成员变量
    void showHello() {
        cout << "Hello, this is a member function!" << endl;
    }

    // 情况2:静态成员函数(无this指针,和空指针无关)
    static void showStatic() {
        cout << "Hello, this is a static member function!" << endl;
    }
};

int main() {
    // 定义空指针
    Person* p = nullptr;

    // 1. 空指针调用不访问成员变量的非静态成员函数 → 正常执行
    p->showHello(); 

    // 2. 空指针调用静态成员函数 → 正常执行(静态函数无this)
    p->showStatic(); 
    // 更规范的写法:Person::showStatic(); (静态函数优先用类名调用)

    return 0;
}
  1. 调用后崩溃的情况(函数内访问成员变量)
cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age;

    // 函数内访问成员变量(会通过this->age访问)
    void showAge() {
        cout << "Age: " << this->age << endl; // 等价于 cout << age;
    }
};

int main() {
    Person* p = nullptr;
    p->showAge(); // 运行崩溃!空指针解引用

    return 0;
}

崩溃原因:

调用p->showAge()时,编译器会把p(空指针)作为this指针传入函数,函数内this->age等价于(nullptr).age------ 对空指针解引用,触发内存访问错误(段错误)。
三、底层原因:成员函数的存储与 this 指针
要理解这个现象,必须回到 C++ 对象模型和this指针的本质:
成员函数的存储:所有非静态成员函数都存储在代码段(全局共享),不属于任何对象,对象的内存中只存成员变量;
调用成员函数的本质:p->func()的逻辑是:
找到Person类的func函数在代码段的地址;
把p的地址作为this指针传入func;
执行func的代码。
空指针调用的关键:
如果func内不使用this指针(不访问成员变量),仅执行固定逻辑,那么即使this是空指针,也能正常执行(因为没解引用this);
如果func内使用this指针(访问成员变量),就会对空指针解引用,触发崩溃。
四、易踩坑的细节补充
const 成员函数也不例外:
const成员函数只是把this限定为const Person
const,但如果this是空指针,访问成员变量依然崩溃:

cpp 复制代码
void showAge() const {
    cout << age << endl; // 崩溃!this是空指针,this->age非法
}

空指针调用虚函数的特殊情况:

虚函数调用依赖this指针指向的虚表指针(vptr),空指针没有 vptr,因此调用虚函数会直接崩溃(无论是否访问成员变量):

cpp 复制代码
class Person {
public:
    virtual void showHello() { // 虚函数
        cout << "Hello" << endl;
    }
};

int main() {
    Person* p = nullptr;
    p->showHello(); // 直接崩溃!需要访问this->vptr
    return 0;
}

语法合法但逻辑非法:

空指针调用成员函数在语法上是允许的(编译器不报错),但逻辑上是错误的 ------ 除非你明确知道函数内不访问成员变量,否则绝对不要这么写。

总结

空指针可以调用非静态、非虚、且不访问成员变量的成员函数(语法合法,运行不崩溃);

空指针调用访问成员变量的成员函数 / 虚函数会崩溃(本质是对空指针解引用);

核心原因:成员函数存在于代码段,调用仅需传入this指针;是否崩溃取决于是否使用this指针访问内存。

开发建议:永远不要用空指针调用成员函数!即使语法上能运行,也是不规范、易出错的写法,可在函数开头加assert(this != nullptr)做校验,提前暴露问题。

相关推荐
小鸡吃米…1 天前
Python 中的并发 —— 进程池
linux·服务器·开发语言·python
Elsa️7461 天前
洛谷p1046:用一个题练习排序+二分查找
c++·算法
小王不爱笑1321 天前
Java 异常全解析:从原理到实战,搞定异常处理
java·开发语言
历程里程碑1 天前
40 UDP - 2 C++实现英汉词典查询服务
linux·开发语言·数据结构·c++·ide·c#·vim
code_whiter1 天前
C++3(类与对象中篇)
c++
叫我一声阿雷吧1 天前
JS 入门通关手册(20):构造函数与原型:JS 面向对象第一课
开发语言·javascript·前端开发·前端面试·构造函数·js进阶·js面向对象
学嵌入式的小杨同学1 天前
STM32 进阶封神之路(十三):空气质量传感器实战 ——KQM6600 模块从协议到代码(串口通信 + 数据解析)
c++·stm32·单片机·嵌入式硬件·架构·硬件架构·嵌入式实时数据库
2501_945423541 天前
C++与Rust交互编程
开发语言·c++·算法
小王不爱笑1321 天前
Java Set 集合全家桶:HashSet、LinkedHashSet、TreeSet 详解与实战
java·开发语言
tankeven1 天前
HJ131 数独数组
c++·算法