C++采坑系列之空指针调用

文摘   2024-12-02 12:06   北京  

你好,我是雨乐~

今天,来聊聊一个常见的问题也是我面试经常问到的一个问题,就是空指针调用

示例代码如下:

#include <iostream>

classObj{
public:
void NonVirtualFunc() {
        std::cout <<"NonVirtualFunc function called.\n";
}
virtual void VirtualFunc() {
        std::cout <<"VirtualFunc function called.\n";
}
};

int main() {
Obj* ptr =nullptr;
ptr->NonVirtualFunc();// #1
ptr->VirtualFunc();// #2
return0;
}

结论

出乎意料的是,这段代码很可能(也有可能崩溃)会输出:

Non-virtual function called.

解释

调用 1:非虚函数

关键在于 C++ 如何处理非虚成员函数。非虚函数可以被看作是接受隐式 this 指针作为第一个参数的普通函数。当我们调用 ptr->NonVirtualFunc() 时,编译器实际上将其转换为类似于以下的代码:

NonVirtualFunc(ptr); // 本质上是这样

因为 NonVirtualFunc 不依赖 this 指针来访问对象的成员变量或调用其他虚函数,它能够在 this 指针为 nullptr 时正常执行,输出预期内容。

重要提示: 这种行为只有在非虚函数不依赖对象的状态(即其成员变量)时才可靠。如果非虚函数依赖于对象的状态,那么你就会陷入未定义行为,可能导致程序崩溃或其他不可预料的错误。

调用 2:虚函数

接下来是谜题的第二部分:

当我们调用 ptr->VirtualFunc() 时,会发生什么?

这次,程序几乎肯定会崩溃,或者抛出与空指针解引用相关的异常。

虚函数的调用是在运行时通过虚函数表(vtable)解析的。当你持有空指针时,无法找到有效的虚函数表,导致程序失败。这个行为是预期中的,并且对于虚函数的多态性机制至关重要。

虚函数的设计目的是根据指针实际指向的对象类型来调用相应的函数,即使该类型是基类的派生类。如果指针为空,则无法确定对象类型,程序只能崩溃。

总结

对空指针调用非虚成员函数,如果该函数不访问对象的成员变量,可能会正常工作。对空指针调用虚成员函数是一个严重错误,几乎肯定会导致程序崩溃。在处理成员函数时,务必小心空指针,以避免未定义行为和潜在的程序崩溃。

如果对本文有异议或者有其他技术问题,可以加微信交流:

推荐阅读  点击标题可跳转

1、手撸一个线程池

2、C++进阶指南:优化程序性能之惰性求值

3、C++采坑系列之父子传参



雨乐聊编程
毕业于中国科学技术大学,现任某互联网公司高级技术专家一职。本公众号专注于技术交流,分享日常有意思的技术点、线上问题等,欢迎关注