You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

指向NULL的类指针可调用普通成员函数、调用虚函数失败的原因是什么?

#include <iostream>
using namespace std;

class Test
{
public:
    void Func1()
    {
        cout << "Func1 called";
    }

    virtual void Func2()
    {
        cout << "Func2 called";
    }
};

int main()
{
    Test* test = NULL;
    test->Func1();
    test->Func2();
}
现象成因分析
  • 普通成员函数Func1的调用逻辑
    C++的普通成员函数在编译阶段就会确定调用地址,编译器会隐式将成员函数转换为带this指针参数的全局函数,上述代码中的Func1会被转换成类似void _Test_Func1(Test* const this)的形式。调用test->Func1()时,只是把test指针的值作为this参数传入该函数,由于Func1内部完全没有用到this指针访问成员变量或其他实例相关资源,哪怕传入的this是NULL,也不会触发内存访问错误,函数可以正常执行。
  • 虚函数Func2的调用逻辑
    虚函数依赖对象实例的虚函数表实现动态绑定:每个包含虚函数的类实例的内存起始位置都会存储一个虚表指针(vptr),指向该类的虚函数表。调用虚函数时,程序需要先从this指针指向的内存地址取出vptr,再从vptr指向的虚表中查询对应虚函数的地址才能执行。本次调用中test为NULL,也就是this指向0地址,尝试读取0地址的vptr时会直接触发内存访问违例(段错误),程序立刻崩溃退出。
  • 无输出的额外原因
    cout默认是行缓冲模式,只有遇到换行符、缓冲区满、程序正常退出时才会将缓冲区的内容刷到控制台。当同时调用Func1和Func2时,Func1的输出还存储在缓冲区中,程序就因为Func2的调用崩溃,缓冲区内容没有被刷新,所以看不到任何输出。如果注释掉Func2的调用,程序可以正常执行结束,缓冲区内容被刷新,就能看到Func1的打印内容。

注意:空指针调用类成员函数本身属于C++标准定义的未定义行为,上述现象仅为大部分主流编译器的实现结果,请勿在生产代码中编写此类逻辑。

内容的提问来源于stack exchange,提问作者sayantan dutta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 05:39:03