调用空指针对象函数

前两天遇到一个挺有意思的问题:

已知有一个class A的实例,A有一个函数func,但不知道A的具体声明和定义。 如果我们有一个ANULL指针A *a = NULL,如果调用a->func()的话,可能会出现什么情况呢?

先不管调用空指针是否是未定义行为。我们从C++语言本身角度去考虑,这样调用是有可能不抛出异常的。

我总结了几个不同的情况,如下(Visual Studio 2012):

#include <iostream>
#include <Windows.h>
#include <exception>

using namespace std;

class A
{
public:
    void func()
    {
        cout << "wtf?" << endl;
    }
    void func_this()
    {
        cout << "wtf: " << this->data << endl;
    }
    static void func_static()
    {
        cout << "static wtf?" << endl;
    }
    virtual void func_virtual()
    {
        cout << "virtual wtf?" << endl;
    }
    A():data(0){}
    int data;
};

int main()
{
    A *a = NULL;
    a->func();
    __try
    {
        a->func_this();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        cout << "cannot invoke func_this" << endl;
    }
    a->func_static();
    __try
    {
        a->func_virtual();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        cout << "cannot invoke func_virtual" << endl;
    }
    return 0;
}

命令行输出结果为:

wtf?
cannot invoke func_this
static wtf?
cannot invoke func_virtual

####分析

我们来依次分析一下能正常运行的func()func_static():

  • 调用func()函数时A指针不是必须的。在编译时,A类型已知,func()函数指针已经可以确认了。
  • 同理,调用静态函数func_static()也不需要实际的实例对象。

对于抛出异常的func_this()func_virtual():

  • func_this()用到了this指针,而this在这样的情况下是NULL,所以会抛出异常。
  • 而调用虚函数func_virtual()时,我们需要一个可用的虚函数表(vtable)指针,但显然这个指针是拿不到的,因此抛出异常。

不过,实际开发中要尽量避免这种情况哟。

####参考

Why does calling method through null pointer “work” in C++?

C++, __try and try/catch/finally