該問題源自於一道面試題,題目如下所示:
看如下代碼,請問能不能編譯通過?如果能編譯通過能不能運行成功?並說明原因
class test
{
public:
int fun(){return 1;};
};
int main ()
{
test *t = NULL;
int res = t->fun();
return 0;
}
好的,我們現在先來分析這道題目,初一看,該代碼應該可以編譯通過,但是運行肯定不會過,因爲t是NULL了嘛,怎麼還能再調用成員函數呢。
現在我們把這段代碼貼到VS裏,編譯,運行,斷點,發現沒報錯,一切正常,res值爲1...
好神奇!
通過查找一些資料,我發現:
因爲函數在類裏面是獨立於類存在的,而且不佔用類的空間,在程序編譯的時候就已經把函數的地址分配好了,因此,只要有這麼一個對象,不管他指向NULL還是非NULL,都是可以調用該函數的,也不會出錯。
那好,既然這樣,我們再來看下面這段代碼:
class test
{
public:
test() {m_num = 0;};
int fun1() {return 1;};
static int fun2() {return 2;};
virtual int fun3() {return 3;};
int fun4() { return m_num;};
private:
int m_num;
};
int main ()
{
test *t = NULL;
int res1 = t->fun1();
int res2 = t->fun2();
int res3 = t->fun3();
int res4 = t->fun4();
return 0;
}
放到編譯器中,fun1,fun2可以正常運行,fun3,fun4運行出錯,這又是爲什麼呢?fun1上面已經分析過了,可以運行沒問題;
fun2是靜態函數,本身就不屬於類,所以跟類的指針沒有關係,可以運行,也沒有問題;
fun3是虛函數,而虛函數是通過虛函數表來實現的,而虛函數表是存在於對象中的,對象爲NULL了,自然就無法訪問了;
fun4是調用了類的成員變量,而成員變量也同樣是存在於類的對象中的,爲NULL的的對象沒有了成員變量的存儲空間,也無法訪問。
以上是對該問題相對錶層的分析,要想進一步瞭解該問題,建議看一下關於“__thiscall”的解釋,可以參考如下博文:
http://blog.csdn.net/yc_8301/article/details/1814744
我也會在後續的文章中專門對該問題做一個分析,敬請關注。